From a92acd6ab2b003f9e78bb3183a4cc56c27793fc7 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 2 Dec 2016 14:38:42 +0100 Subject: [PATCH 01/45] move files around and rename some to be more consistent --- frontend/package.json | 14 +++--- .../AllocationFiles.js} | 2 +- .../AllocationInfo.js} | 8 ++-- .../AllocationList.js} | 46 ++++++++++++++++-- .../raw.js => AllocationRaw/AllocationRaw.js} | 4 +- .../ClientAllocations.js} | 2 +- .../ClientEvaluations.js} | 2 +- .../info.js => ClientInfo/ClientInfo.js} | 14 +++--- .../{client/raw.js => ClientRaw/ClientRaw.js} | 4 +- .../row.js => ConstraintRow/ConstraintRow.js} | 0 .../ConstraintTable.js} | 2 +- .../EvaluationAllocations.js} | 8 ++-- .../EvaluationInfo.js} | 0 .../EvaluationList.js} | 2 +- .../raw.js => EvaluationRaw/EvaluationRaw.js} | 4 +- .../FormatBoolean.js} | 0 .../time.js => FormatTime/FormatTime.js} | 0 .../JobAllocations.js} | 11 +++-- .../JobEvaluations.js} | 11 +++-- .../{job/info.js => JobInfo/JobInfo.js} | 12 ++--- .../{job/raw.js => JobRaw/JobRaw.js} | 4 +- .../JobTaskGroups.js} | 12 ++--- .../{job/tasks.js => JobTasks/JobTasks.js} | 8 ++-- .../{meta.js => MetaPayload/MetaPayload.js} | 8 ++-- .../status.js => NodeStatus/NodeStatus.js} | 2 +- .../{link.js => NomadLink/NomadLink.js} | 3 +- .../Progressbar.js} | 0 .../{json.js => RawJson/RawJson.js} | 0 .../info.js => ServerInfo/ServerInfo.js} | 3 +- .../{server/raw.js => ServerRaw/ServerRaw.js} | 4 +- .../{sidebar.js => Sidebar/Sidebar.js} | 0 .../components/{table.js => Table/Table.js} | 0 .../src/components/{tabs.js => Tabs/Tabs.js} | 0 .../{topbar.js => Topbar/Topbar.js} | 0 frontend/src/components/app.js | 4 +- frontend/src/containers/allocation.js | 4 +- frontend/src/containers/allocations.js | 2 +- frontend/src/containers/client.js | 4 +- frontend/src/containers/clients.js | 6 +-- frontend/src/containers/cluster.js | 2 +- frontend/src/containers/evaluation.js | 4 +- frontend/src/containers/evaluations.js | 2 +- frontend/src/containers/events.js | 4 +- frontend/src/containers/job.js | 4 +- frontend/src/containers/jobs.js | 47 ++++++++++++++++++- frontend/src/containers/server.js | 4 +- frontend/src/containers/servers.js | 4 +- frontend/src/containers/statistics.js | 2 +- frontend/src/helpers/render/allocation.js | 40 ---------------- frontend/src/helpers/statistics.js | 45 ------------------ frontend/src/helpers/uuid.js | 8 +--- frontend/src/router.js | 38 +++++++-------- 52 files changed, 198 insertions(+), 216 deletions(-) rename frontend/src/components/{allocation/files.js => AllocationFiles/AllocationFiles.js} (99%) rename frontend/src/components/{allocation/info.js => AllocationInfo/AllocationInfo.js} (95%) rename frontend/src/components/{allocation/list.js => AllocationList/AllocationList.js} (86%) rename frontend/src/components/{allocation/raw.js => AllocationRaw/AllocationRaw.js} (82%) rename frontend/src/components/{client/allocations.js => ClientAllocations/ClientAllocations.js} (94%) rename frontend/src/components/{client/evaluations.js => ClientEvaluations/ClientEvaluations.js} (92%) rename frontend/src/components/{client/info.js => ClientInfo/ClientInfo.js} (82%) rename frontend/src/components/{client/raw.js => ClientRaw/ClientRaw.js} (83%) rename frontend/src/components/{constraint/row.js => ConstraintRow/ConstraintRow.js} (100%) rename frontend/src/components/{constraint/table.js => ConstraintTable/ConstraintTable.js} (96%) rename frontend/src/components/{evaluation/allocs.js => EvaluationAllocations/EvaluationAllocations.js} (69%) rename frontend/src/components/{evaluation/info.js => EvaluationInfo/EvaluationInfo.js} (100%) rename frontend/src/components/{evaluation/list.js => EvaluationList/EvaluationList.js} (96%) rename frontend/src/components/{evaluation/raw.js => EvaluationRaw/EvaluationRaw.js} (82%) rename frontend/src/components/{format/boolean.js => FormatBoolean/FormatBoolean.js} (100%) rename frontend/src/components/{format/time.js => FormatTime/FormatTime.js} (100%) rename frontend/src/components/{job/allocs.js => JobAllocations/JobAllocations.js} (80%) rename frontend/src/components/{job/evals.js => JobEvaluations/JobEvaluations.js} (74%) rename frontend/src/components/{job/info.js => JobInfo/JobInfo.js} (93%) rename frontend/src/components/{job/raw.js => JobRaw/JobRaw.js} (82%) rename frontend/src/components/{job/taskGroups.js => JobTaskGroups/JobTaskGroups.js} (85%) rename frontend/src/components/{job/tasks.js => JobTasks/JobTasks.js} (93%) rename frontend/src/components/{meta.js => MetaPayload/MetaPayload.js} (92%) rename frontend/src/components/{node/status.js => NodeStatus/NodeStatus.js} (90%) rename frontend/src/components/{link.js => NomadLink/NomadLink.js} (99%) rename frontend/src/components/{charts/progressbar.js => Progressbar/Progressbar.js} (100%) rename frontend/src/components/{json.js => RawJson/RawJson.js} (100%) rename frontend/src/components/{server/info.js => ServerInfo/ServerInfo.js} (97%) rename frontend/src/components/{server/raw.js => ServerRaw/ServerRaw.js} (82%) rename frontend/src/components/{sidebar.js => Sidebar/Sidebar.js} (100%) rename frontend/src/components/{table.js => Table/Table.js} (100%) rename frontend/src/components/{tabs.js => Tabs/Tabs.js} (100%) rename frontend/src/components/{topbar.js => Topbar/Topbar.js} (100%) delete mode 100644 frontend/src/helpers/render/allocation.js delete mode 100644 frontend/src/helpers/statistics.js diff --git a/frontend/package.json b/frontend/package.json index 1b334a05..5dd9a0d4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -30,14 +30,14 @@ "moment": "^2.15.1", "moment-duration-format": "^1.3.0", "node-uuid": "^1.4.7", - "react": "^15.2.1", - "react-bootstrap": "^0.30.3", - "react-dom": "^15.2.1", - "react-redux": "^4.4.5", - "react-router": "^2.5.2", + "react": "^15.4.1", + "react-bootstrap": "^0.30.7", + "react-dom": "^15.4.1", + "react-redux": "^4.4.6", + "react-router": "^2.8.1", "react-tooltip": "^3.1.8", - "redux": "^3.5.2", - "redux-saga": "^0.11.0", + "redux": "^3.6.0", + "redux-saga": "^0.13.0", "superagent": "^2.1.0" }, "devDependencies": { diff --git a/frontend/src/components/allocation/files.js b/frontend/src/components/AllocationFiles/AllocationFiles.js similarity index 99% rename from frontend/src/components/allocation/files.js rename to frontend/src/components/AllocationFiles/AllocationFiles.js index 2c1ae97e..09b037d1 100644 --- a/frontend/src/components/allocation/files.js +++ b/frontend/src/components/AllocationFiles/AllocationFiles.js @@ -2,7 +2,7 @@ import React, { Component, PropTypes } from 'react'; import ReactTooltip from 'react-tooltip'; import { connect } from 'react-redux'; import { Button } from 'react-bootstrap'; -import Table from '../table'; +import Table from '../Table/Table'; import { FETCH_NODE, FETCH_DIR, diff --git a/frontend/src/components/allocation/info.js b/frontend/src/components/AllocationInfo/AllocationInfo.js similarity index 95% rename from frontend/src/components/allocation/info.js rename to frontend/src/components/AllocationInfo/AllocationInfo.js index 78dc8be4..d334d200 100644 --- a/frontend/src/components/allocation/info.js +++ b/frontend/src/components/AllocationInfo/AllocationInfo.js @@ -1,9 +1,9 @@ import React, { Component, PropTypes } from 'react'; import { Panel, Accordion, Table } from 'react-bootstrap'; import { connect } from 'react-redux'; -import NomadLink from '../link'; -import Meta from '../meta'; -import FormatTime from '../format/time'; +import NomadLink from '../NomadLink/NomadLink'; +import MetaPayload from '../MetaPayload/MetaPayload'; +import FormatTime from '../FormatTime/FormatTime'; const allocProps = [ 'ID', @@ -115,7 +115,7 @@ class AllocationInfo extends Component {
Allocation Properties - +
diff --git a/frontend/src/components/allocation/list.js b/frontend/src/components/AllocationList/AllocationList.js similarity index 86% rename from frontend/src/components/allocation/list.js rename to frontend/src/components/AllocationList/AllocationList.js index 13683daa..e3623739 100644 --- a/frontend/src/components/allocation/list.js +++ b/frontend/src/components/AllocationList/AllocationList.js @@ -1,16 +1,23 @@ import React, { Component, PropTypes } from 'react'; import { DropdownButton, Glyphicon } from 'react-bootstrap'; import { Link } from 'react-router'; -import NomadLink from '../link'; -import FormatTime from '../format/time'; +import NomadLink from '../NomadLink/NomadLink'; +import FormatTime from '../FormatTime/FormatTime'; import shortUUID from '../../helpers/uuid'; -import { renderDesiredStatus, renderClientStatus } from '../../helpers/render/allocation'; +import ReactTooltip from 'react-tooltip'; const getAllocationNumberFromName = (allocationName) => { const match = /[\d+]/.exec(allocationName); return match[0]; }; +const clientStatusIcon = { + complete: , + running: , + lost: , + failed: , +}; + const optionsGlyph = ; const jobHeaderColumn = display => @@ -25,6 +32,36 @@ const clientHeaderColumn = display => const clientColumn = (allocation, nodes, display) => (display ? : null); +const renderDesiredStatus = (allocation) => { + if (allocation.DesiredDescription) { + return ( +
+ {allocation.DesiredDescription} + + {allocation.DesiredStatus} + +
+ ); + } + + return
{allocation.DesiredStatus}
; +} + +const renderClientStatus = (allocation) => { + let icon = null; + + if (allocation.ClientStatus in clientStatusIcon) { + icon = clientStatusIcon[allocation.ClientStatus]; + } + + return ( +
+ {allocation.ClientStatus} + {icon} +
+ ); +} + let nodeIdToNameCache = {}; class AllocationList extends Component { @@ -87,6 +124,7 @@ class AllocationList extends Component {
  • - Any -
  • Running
  • Complete
  • +
  • Pending
  • Lost
  • Failed
  • @@ -188,7 +226,7 @@ class AllocationList extends Component { ID { jobHeaderColumn(showJobColumn) } - Task Group + Task Group Status { clientHeaderColumn(showClientColumn) } Age diff --git a/frontend/src/components/allocation/raw.js b/frontend/src/components/AllocationRaw/AllocationRaw.js similarity index 82% rename from frontend/src/components/allocation/raw.js rename to frontend/src/components/AllocationRaw/AllocationRaw.js index 8fad70ca..70f688d4 100644 --- a/frontend/src/components/allocation/raw.js +++ b/frontend/src/components/AllocationRaw/AllocationRaw.js @@ -1,11 +1,11 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; -import Json from '../json'; +import RawJson from '../RawJson/RawJson'; const AllocationRaw = ({ allocation }) =>
    - +
    ; function mapStateToProps({ allocation }) { diff --git a/frontend/src/components/client/allocations.js b/frontend/src/components/ClientAllocations/ClientAllocations.js similarity index 94% rename from frontend/src/components/client/allocations.js rename to frontend/src/components/ClientAllocations/ClientAllocations.js index a5974297..c669a4cf 100644 --- a/frontend/src/components/client/allocations.js +++ b/frontend/src/components/ClientAllocations/ClientAllocations.js @@ -1,6 +1,6 @@ import React, { PureComponent, PropTypes } from 'react'; import { connect } from 'react-redux'; -import AllocationList from '../allocation/list'; +import AllocationList from '../AllocationList/AllocationList'; class ClientAllocations extends PureComponent { diff --git a/frontend/src/components/client/evaluations.js b/frontend/src/components/ClientEvaluations/ClientEvaluations.js similarity index 92% rename from frontend/src/components/client/evaluations.js rename to frontend/src/components/ClientEvaluations/ClientEvaluations.js index bd38b7d8..64e1ed6d 100644 --- a/frontend/src/components/client/evaluations.js +++ b/frontend/src/components/ClientEvaluations/ClientEvaluations.js @@ -1,6 +1,6 @@ import React, { PureComponent, PropTypes } from 'react'; import { connect } from 'react-redux'; -import EvaluationList from '../evaluation/list'; +import EvaluationList from '../EvaluationList/EvaluationList'; class ClientEvaluations extends PureComponent { diff --git a/frontend/src/components/client/info.js b/frontend/src/components/ClientInfo/ClientInfo.js similarity index 82% rename from frontend/src/components/client/info.js rename to frontend/src/components/ClientInfo/ClientInfo.js index ef9cb370..6afd85ac 100644 --- a/frontend/src/components/client/info.js +++ b/frontend/src/components/ClientInfo/ClientInfo.js @@ -1,6 +1,6 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; -import MetaDisplay from '../meta'; +import MetaPayload from '../MetaPayload/MetaPayload'; const nodeProps = [ 'ID', @@ -40,29 +40,29 @@ const ClientInfo = ({ node }) =>
    Meta Properties - +
    CPU Attributes - +
    Driver Attributes - +
    Kernel Attributes - +
    Unique Attributes - +
    Nomad Attributes - +
    ; diff --git a/frontend/src/components/client/raw.js b/frontend/src/components/ClientRaw/ClientRaw.js similarity index 83% rename from frontend/src/components/client/raw.js rename to frontend/src/components/ClientRaw/ClientRaw.js index 0cb1936d..b263bf6a 100644 --- a/frontend/src/components/client/raw.js +++ b/frontend/src/components/ClientRaw/ClientRaw.js @@ -1,12 +1,12 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; -import Json from '../json'; +import RawJson from '../RawJson/RawJson'; const ClientRaw = ({ node }) =>
    - +
    ; diff --git a/frontend/src/components/constraint/row.js b/frontend/src/components/ConstraintRow/ConstraintRow.js similarity index 100% rename from frontend/src/components/constraint/row.js rename to frontend/src/components/ConstraintRow/ConstraintRow.js diff --git a/frontend/src/components/constraint/table.js b/frontend/src/components/ConstraintTable/ConstraintTable.js similarity index 96% rename from frontend/src/components/constraint/table.js rename to frontend/src/components/ConstraintTable/ConstraintTable.js index f3e3a40d..e860ad27 100644 --- a/frontend/src/components/constraint/table.js +++ b/frontend/src/components/ConstraintTable/ConstraintTable.js @@ -1,6 +1,6 @@ import React, { Component, PropTypes } from 'react'; import ReactTooltip from 'react-tooltip'; -import ConstraintRow from './row'; +import ConstraintRow from '../ConstraintRow/ConstraintRow'; class ConstraintTable extends Component { diff --git a/frontend/src/components/evaluation/allocs.js b/frontend/src/components/EvaluationAllocations/EvaluationAllocations.js similarity index 69% rename from frontend/src/components/evaluation/allocs.js rename to frontend/src/components/EvaluationAllocations/EvaluationAllocations.js index 2ada1988..2e3161ee 100644 --- a/frontend/src/components/evaluation/allocs.js +++ b/frontend/src/components/EvaluationAllocations/EvaluationAllocations.js @@ -1,8 +1,8 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; -import AllocationList from '../allocation/list'; +import AllocationList from '../AllocationList/AllocationList'; -const EvaluationAllocs = ({ allocations, evaluation, nodes }) => { +const EvaluationAllocations = ({ allocations, evaluation, nodes }) => { const allocs = allocations.filter(allocation => allocation.EvalID === evaluation.ID); return ( @@ -14,10 +14,10 @@ function mapStateToProps({ evaluation, allocations, nodes }) { return { evaluation, allocations, nodes }; } -EvaluationAllocs.propTypes = { +EvaluationAllocations.propTypes = { allocations: PropTypes.array.isRequired, evaluation: PropTypes.object.isRequired, nodes: PropTypes.array.isRequired, }; -export default connect(mapStateToProps)(EvaluationAllocs); +export default connect(mapStateToProps)(EvaluationAllocations); diff --git a/frontend/src/components/evaluation/info.js b/frontend/src/components/EvaluationInfo/EvaluationInfo.js similarity index 100% rename from frontend/src/components/evaluation/info.js rename to frontend/src/components/EvaluationInfo/EvaluationInfo.js diff --git a/frontend/src/components/evaluation/list.js b/frontend/src/components/EvaluationList/EvaluationList.js similarity index 96% rename from frontend/src/components/evaluation/list.js rename to frontend/src/components/EvaluationList/EvaluationList.js index 7bb2cc2f..bafac45f 100644 --- a/frontend/src/components/evaluation/list.js +++ b/frontend/src/components/EvaluationList/EvaluationList.js @@ -1,5 +1,5 @@ import React, { PropTypes } from 'react'; -import NomadLink from '../link'; +import NomadLink from '../NomadLink/NomadLink'; const EvaluationList = ({ evaluations, containerClassName }) =>
    diff --git a/frontend/src/components/evaluation/raw.js b/frontend/src/components/EvaluationRaw/EvaluationRaw.js similarity index 82% rename from frontend/src/components/evaluation/raw.js rename to frontend/src/components/EvaluationRaw/EvaluationRaw.js index 10b65153..774e617e 100644 --- a/frontend/src/components/evaluation/raw.js +++ b/frontend/src/components/EvaluationRaw/EvaluationRaw.js @@ -1,11 +1,11 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; -import Json from '../json'; +import RawJson from '../RawJson/RawJson'; const EvaluationRaw = ({ evaluation }) =>
    - +
    ; function mapStateToProps({ evaluation }) { diff --git a/frontend/src/components/format/boolean.js b/frontend/src/components/FormatBoolean/FormatBoolean.js similarity index 100% rename from frontend/src/components/format/boolean.js rename to frontend/src/components/FormatBoolean/FormatBoolean.js diff --git a/frontend/src/components/format/time.js b/frontend/src/components/FormatTime/FormatTime.js similarity index 100% rename from frontend/src/components/format/time.js rename to frontend/src/components/FormatTime/FormatTime.js diff --git a/frontend/src/components/job/allocs.js b/frontend/src/components/JobAllocations/JobAllocations.js similarity index 80% rename from frontend/src/components/job/allocs.js rename to frontend/src/components/JobAllocations/JobAllocations.js index 33372905..c6e1c690 100644 --- a/frontend/src/components/job/allocs.js +++ b/frontend/src/components/JobAllocations/JobAllocations.js @@ -1,8 +1,8 @@ import React, { PureComponent, PropTypes } from 'react'; import { connect } from 'react-redux'; -import AllocationList from '../allocation/list'; +import AllocationList from '../AllocationList/AllocationList'; -class JobAllocs extends PureComponent { +class JobAllocations extends PureComponent { render() { const jobId = this.props.params.jobId; @@ -28,18 +28,19 @@ function mapStateToProps({ allocations, nodes }) { return { allocations, nodes }; } -JobAllocs.defaultProps = { +JobAllocations.defaultProps = { allocations: [], nodes: [], params: {}, location: {}, }; -JobAllocs.propTypes = { +JobAllocations.propTypes = { allocations: PropTypes.array.isRequired, params: PropTypes.object.isRequired, nodes: PropTypes.array.isRequired, location: PropTypes.object.isRequired, }; -export default connect(mapStateToProps)(JobAllocs); +export default connect(mapStateToProps)(JobAllocations); + diff --git a/frontend/src/components/job/evals.js b/frontend/src/components/JobEvaluations/JobEvaluations.js similarity index 74% rename from frontend/src/components/job/evals.js rename to frontend/src/components/JobEvaluations/JobEvaluations.js index fd80540a..31c10ddd 100644 --- a/frontend/src/components/job/evals.js +++ b/frontend/src/components/JobEvaluations/JobEvaluations.js @@ -1,8 +1,8 @@ import React, { PureComponent, PropTypes } from 'react'; import { connect } from 'react-redux'; -import EvaluationList from '../evaluation/list'; +import EvaluationList from '../EvaluationList/EvaluationList'; -class JobEvals extends PureComponent { +class JobEvaluations extends PureComponent { render() { const jobId = this.props.params.jobId; @@ -20,14 +20,15 @@ function mapStateToProps({ evaluations }) { return { evaluations }; } -JobEvals.defaultProps = { +JobEvaluations.defaultProps = { evaluations: [], params: {}, }; -JobEvals.propTypes = { +JobEvaluations.propTypes = { evaluations: PropTypes.array.isRequired, params: PropTypes.object.isRequired, }; -export default connect(mapStateToProps)(JobEvals); +export default connect(mapStateToProps)(JobEvaluations); + diff --git a/frontend/src/components/job/info.js b/frontend/src/components/JobInfo/JobInfo.js similarity index 93% rename from frontend/src/components/job/info.js rename to frontend/src/components/JobInfo/JobInfo.js index 694dec30..7857eb62 100644 --- a/frontend/src/components/job/info.js +++ b/frontend/src/components/JobInfo/JobInfo.js @@ -1,9 +1,9 @@ import React, { Component, PropTypes } from 'react'; import { connect } from 'react-redux'; -import NomadLink from '../link'; -import Table from '../table'; -import MetaDisplay from '../meta'; -import ConstraintTable from '../constraint/table'; +import NomadLink from '../NomadLink/NomadLink'; +import Table from '../Table/Table'; +import MetaPayload from '../MetaPayload/MetaPayload'; +import ConstraintTable from '../ConstraintTable/ConstraintTable'; const jobProps = ['ID', 'Name', 'Region', 'Datacenters', 'Status', 'Priority']; @@ -49,7 +49,7 @@ class JobInfo extends Component { { taskGroup.Count } { taskGroup.Tasks.length } - + { taskGroup.RestartPolicy.Mode } @@ -78,7 +78,7 @@ class JobInfo extends Component {
    Meta Properties - +
    diff --git a/frontend/src/components/job/raw.js b/frontend/src/components/JobRaw/JobRaw.js similarity index 82% rename from frontend/src/components/job/raw.js rename to frontend/src/components/JobRaw/JobRaw.js index 3cd03e79..d3adb45e 100644 --- a/frontend/src/components/job/raw.js +++ b/frontend/src/components/JobRaw/JobRaw.js @@ -1,11 +1,11 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; -import Json from '../json'; +import RawJson from '../RawJson/RawJson'; const JobRaw = ({ job }) =>
    - +
    ; function mapStateToProps({ job }) { diff --git a/frontend/src/components/job/taskGroups.js b/frontend/src/components/JobTaskGroups/JobTaskGroups.js similarity index 85% rename from frontend/src/components/job/taskGroups.js rename to frontend/src/components/JobTaskGroups/JobTaskGroups.js index eddd869f..43e42fb8 100644 --- a/frontend/src/components/job/taskGroups.js +++ b/frontend/src/components/JobTaskGroups/JobTaskGroups.js @@ -1,9 +1,9 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; -import NomadLink from '../link'; -import Table from '../table'; -import Json from '../json'; -import MetaDisplay from '../meta'; +import NomadLink from '../NomadLink/NomadLink'; +import Table from '../Table/Table'; +import RawJson from '../RawJson/RawJson'; +import MetaPayload from '../MetaPayload/MetaPayload'; const taskGroupHeaders = [ 'ID', @@ -22,7 +22,7 @@ const JobTaskGroups = ({ job, location }) => { { taskGroup.Name } { taskGroup.Count } - + { taskGroup.RestartPolicy.Mode } ); @@ -52,7 +52,7 @@ const JobTaskGroups = ({ job, location }) => { Task Group: { taskGroupId } { job.TaskGroups .filter(taskGroup => taskGroup.ID === taskGroupId) - .map(taskGroup => ) + .map(taskGroup => ) .pop() } diff --git a/frontend/src/components/job/tasks.js b/frontend/src/components/JobTasks/JobTasks.js similarity index 93% rename from frontend/src/components/job/tasks.js rename to frontend/src/components/JobTasks/JobTasks.js index 6904a21b..6624a53b 100644 --- a/frontend/src/components/job/tasks.js +++ b/frontend/src/components/JobTasks/JobTasks.js @@ -1,8 +1,8 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; -import NomadLink from '../link'; -import Table from '../table'; -import Json from '../json'; +import NomadLink from '../NomadLink/NomadLink'; +import Table from '../Table/Table'; +import RawJson from '../RawJson/RawJson'; const taskHeaders = [ 'ID', @@ -75,7 +75,7 @@ const JobTasks = ({ job, location }) => { .filter(taskGroup => taskGroup.ID === taskGroupId) .map(taskGroup => taskGroup.Tasks .filter(task => task.ID === taskId) - .map(task => ) + .map(task => ) .pop()) .pop()} diff --git a/frontend/src/components/meta.js b/frontend/src/components/MetaPayload/MetaPayload.js similarity index 92% rename from frontend/src/components/meta.js rename to frontend/src/components/MetaPayload/MetaPayload.js index 3b522986..fd0e84c8 100644 --- a/frontend/src/components/meta.js +++ b/frontend/src/components/MetaPayload/MetaPayload.js @@ -2,7 +2,7 @@ import React, { Component, PropTypes } from 'react'; import ReactTooltip from 'react-tooltip'; import uuid from 'node-uuid'; -class Meta extends Component { +class MetaPayload extends Component { render() { const metaBag = this.props.metaBag || {}; @@ -45,18 +45,18 @@ class Meta extends Component { } } -Meta.defaultProps = { +MetaPayload.defaultProps = { metaBag: {}, dtWithClass: 'default', sortKeys: true, asTooltip: false, }; -Meta.propTypes = { +MetaPayload.propTypes = { metaBag: PropTypes.object, dtWithClass: PropTypes.string.isRequired, sortKeys: PropTypes.bool.isRequired, asTooltip: PropTypes.bool.isRequired, }; -export default Meta; +export default MetaPayload; diff --git a/frontend/src/components/node/status.js b/frontend/src/components/NodeStatus/NodeStatus.js similarity index 90% rename from frontend/src/components/node/status.js rename to frontend/src/components/NodeStatus/NodeStatus.js index 623ea2b7..173470b4 100644 --- a/frontend/src/components/node/status.js +++ b/frontend/src/components/NodeStatus/NodeStatus.js @@ -1,5 +1,5 @@ import React, { PropTypes } from 'react'; -import FormatBoolean from '../format/boolean'; +import FormatBoolean from '../FormatBoolean/FormatBoolean'; const NodeStatus = ({ value }) => { switch (value) { diff --git a/frontend/src/components/link.js b/frontend/src/components/NomadLink/NomadLink.js similarity index 99% rename from frontend/src/components/link.js rename to frontend/src/components/NomadLink/NomadLink.js index 47292e43..610d9fd9 100644 --- a/frontend/src/components/link.js +++ b/frontend/src/components/NomadLink/NomadLink.js @@ -1,6 +1,6 @@ import React, { Component, PropTypes } from 'react'; import { Link } from 'react-router'; -import shortUUID from '../helpers/uuid'; +import shortUUID from '../../helpers/uuid'; let nodeIdToNameCache = {}; @@ -126,6 +126,7 @@ export default class NomadLink extends Component { if (children === undefined) { children = short ? shortUUID(taskGroupId) : taskGroupId; } + return ( { children } diff --git a/frontend/src/components/charts/progressbar.js b/frontend/src/components/Progressbar/Progressbar.js similarity index 100% rename from frontend/src/components/charts/progressbar.js rename to frontend/src/components/Progressbar/Progressbar.js diff --git a/frontend/src/components/json.js b/frontend/src/components/RawJson/RawJson.js similarity index 100% rename from frontend/src/components/json.js rename to frontend/src/components/RawJson/RawJson.js diff --git a/frontend/src/components/server/info.js b/frontend/src/components/ServerInfo/ServerInfo.js similarity index 97% rename from frontend/src/components/server/info.js rename to frontend/src/components/ServerInfo/ServerInfo.js index 310f21a7..a628da6e 100644 --- a/frontend/src/components/server/info.js +++ b/frontend/src/components/ServerInfo/ServerInfo.js @@ -1,7 +1,6 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; - -import Table from '../table'; +import Table from '../Table/Table'; const memberProps = [ 'ID', diff --git a/frontend/src/components/server/raw.js b/frontend/src/components/ServerRaw/ServerRaw.js similarity index 82% rename from frontend/src/components/server/raw.js rename to frontend/src/components/ServerRaw/ServerRaw.js index e95a68da..e7ce8363 100644 --- a/frontend/src/components/server/raw.js +++ b/frontend/src/components/ServerRaw/ServerRaw.js @@ -1,11 +1,11 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; -import Json from '../json'; +import RawJson from '../RawJson/RawJson'; const ServerRaw = ({ member }) =>
    - +
    ; function mapStateToProps({ member }) { diff --git a/frontend/src/components/sidebar.js b/frontend/src/components/Sidebar/Sidebar.js similarity index 100% rename from frontend/src/components/sidebar.js rename to frontend/src/components/Sidebar/Sidebar.js diff --git a/frontend/src/components/table.js b/frontend/src/components/Table/Table.js similarity index 100% rename from frontend/src/components/table.js rename to frontend/src/components/Table/Table.js diff --git a/frontend/src/components/tabs.js b/frontend/src/components/Tabs/Tabs.js similarity index 100% rename from frontend/src/components/tabs.js rename to frontend/src/components/Tabs/Tabs.js diff --git a/frontend/src/components/topbar.js b/frontend/src/components/Topbar/Topbar.js similarity index 100% rename from frontend/src/components/topbar.js rename to frontend/src/components/Topbar/Topbar.js diff --git a/frontend/src/components/app.js b/frontend/src/components/app.js index 5d687f6c..605d9711 100644 --- a/frontend/src/components/app.js +++ b/frontend/src/components/app.js @@ -1,6 +1,6 @@ import React, { PureComponent, PropTypes } from 'react'; -import Sidebar from './sidebar'; -import Topbar from './topbar'; +import Sidebar from './Sidebar/Sidebar'; +import Topbar from './Topbar/Topbar'; class App extends PureComponent { diff --git a/frontend/src/containers/allocation.js b/frontend/src/containers/allocation.js index 82f08d92..1d31f3da 100644 --- a/frontend/src/containers/allocation.js +++ b/frontend/src/containers/allocation.js @@ -1,8 +1,6 @@ import React, { Component, PropTypes } from 'react'; import { connect } from 'react-redux'; - -import Tabs from '../components/tabs'; - +import Tabs from '../components/Tabs/Tabs'; import { WATCH_ALLOC, UNWATCH_ALLOC } from '../sagas/event'; class Allocation extends Component { diff --git a/frontend/src/containers/allocations.js b/frontend/src/containers/allocations.js index 2a9ca43a..5fee7dbb 100644 --- a/frontend/src/containers/allocations.js +++ b/frontend/src/containers/allocations.js @@ -1,6 +1,6 @@ import React, { Component, PropTypes } from 'react'; import { connect } from 'react-redux'; -import AllocationList from '../components/allocation/list'; +import AllocationList from '../components/AllocationList/AllocationList'; class Allocations extends Component { diff --git a/frontend/src/containers/client.js b/frontend/src/containers/client.js index 542511d9..5e2d733e 100644 --- a/frontend/src/containers/client.js +++ b/frontend/src/containers/client.js @@ -1,8 +1,6 @@ import React, { Component, PropTypes } from 'react'; import { connect } from 'react-redux'; - -import Tabs from '../components/tabs'; - +import Tabs from '../components/Tabs/Tabs'; import { WATCH_NODE, UNWATCH_NODE } from '../sagas/event'; class Client extends Component { diff --git a/frontend/src/containers/clients.js b/frontend/src/containers/clients.js index a062eb98..b1c39ccb 100644 --- a/frontend/src/containers/clients.js +++ b/frontend/src/containers/clients.js @@ -1,8 +1,8 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; -import NomadLink from '../components/link'; -import FormatBoolean from '../components/format/boolean'; -import NodeStatus from '../components/node/status'; +import NomadLink from '../components/NomadLink/NomadLink'; +import FormatBoolean from '../components/FormatBoolean/FormatBoolean'; +import NodeStatus from '../components/NodeStatus/NodeStatus'; const Clients = ({ nodes }) =>
    diff --git a/frontend/src/containers/cluster.js b/frontend/src/containers/cluster.js index 20e2b579..d79f700c 100644 --- a/frontend/src/containers/cluster.js +++ b/frontend/src/containers/cluster.js @@ -1,6 +1,6 @@ import React, { Component, PropTypes } from 'react'; import { connect } from 'react-redux'; -import Progressbar from '../components/charts/progressbar'; +import Progressbar from '../components/Progressbar/Progressbar'; import Events from './events'; import Statistics from './statistics'; diff --git a/frontend/src/containers/evaluation.js b/frontend/src/containers/evaluation.js index b7a1aece..e8b9604a 100644 --- a/frontend/src/containers/evaluation.js +++ b/frontend/src/containers/evaluation.js @@ -1,8 +1,6 @@ import React, { Component, PropTypes } from 'react'; import { connect } from 'react-redux'; - -import Tabs from '../components/tabs'; - +import Tabs from '../components/Tabs/Tabs'; import { WATCH_EVAL, UNWATCH_EVAL } from '../sagas/event'; class Evaluation extends Component { diff --git a/frontend/src/containers/evaluations.js b/frontend/src/containers/evaluations.js index 28bec03b..aaa9d7c3 100644 --- a/frontend/src/containers/evaluations.js +++ b/frontend/src/containers/evaluations.js @@ -1,6 +1,6 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; -import EvaluationList from '../components/evaluation/list'; +import EvaluationList from '../components/EvaluationList/EvaluationList'; const Evaluations = ({ evaluations }) =>
    diff --git a/frontend/src/containers/events.js b/frontend/src/containers/events.js index 27b757e4..9a1edbdf 100644 --- a/frontend/src/containers/events.js +++ b/frontend/src/containers/events.js @@ -1,7 +1,7 @@ import React, { Component, PropTypes } from 'react'; import { connect } from 'react-redux'; -import NomadLink from '../components/link'; -import FormatTime from '../components/format/time'; +import NomadLink from '../components/NomadLink/NomadLink'; +import FormatTime from '../components/FormatTime/FormatTime'; class Events extends Component { diff --git a/frontend/src/containers/job.js b/frontend/src/containers/job.js index 7f42d1f6..0349ea5f 100644 --- a/frontend/src/containers/job.js +++ b/frontend/src/containers/job.js @@ -1,8 +1,6 @@ import React, { Component, PropTypes } from 'react'; import { connect } from 'react-redux'; - -import Tabs from '../components/tabs'; - +import Tabs from '../components/Tabs/Tabs'; import { WATCH_JOB, UNWATCH_JOB } from '../sagas/event'; class Job extends Component { diff --git a/frontend/src/containers/jobs.js b/frontend/src/containers/jobs.js index e8ad0b18..885f8a83 100644 --- a/frontend/src/containers/jobs.js +++ b/frontend/src/containers/jobs.js @@ -2,8 +2,7 @@ import React, { Component, PropTypes } from 'react'; import { connect } from 'react-redux'; import { Link } from 'react-router'; import { DropdownButton } from 'react-bootstrap'; -import { getJobStatisticsHeader, getJobStatisticsRow } from '../helpers/statistics'; -import NomadLink from '../components/link'; +import NomadLink from '../components/NomadLink/NomadLink'; const jobStatusColors = { running: '', @@ -11,6 +10,50 @@ const jobStatusColors = { dead: 'danger', }; +const summaryLabels = ['Starting', 'Running', 'Queued', 'Complete', 'Failed', 'Lost']; + +const getJobStatisticsHeader = () => { + const output = []; + + summaryLabels.forEach((key) => { + output.push({ key }); + }); + + return output; +} + +const getJobStatisticsRow = (job) => { + const counter = { + Queued: 0, + Complete: 0, + Failed: 0, + Running: 0, + Starting: 0, + Lost: 0, + }; + + if (job.JobSummary !== null) { + const summary = job.JobSummary.Summary; + Object.keys(summary).forEach((taskGroupID) => { + counter.Queued += summary[taskGroupID].Queued; + counter.Complete += summary[taskGroupID].Complete; + counter.Failed += summary[taskGroupID].Failed; + counter.Running += summary[taskGroupID].Running; + counter.Starting += summary[taskGroupID].Starting; + counter.Lost += summary[taskGroupID].Lost; + }); + } else { + Object.keys(counter).forEach(key => (counter[key] = 'N/A')); + } + + const output = []; + summaryLabels.forEach((key) => { + output.push({counter[key]}); + }); + + return output; +} + class Jobs extends Component { filteredJobs() { diff --git a/frontend/src/containers/server.js b/frontend/src/containers/server.js index 6166f0fb..4bbaae33 100644 --- a/frontend/src/containers/server.js +++ b/frontend/src/containers/server.js @@ -1,8 +1,6 @@ import React, { Component, PropTypes } from 'react'; import { connect } from 'react-redux'; - -import Tabs from '../components/tabs'; - +import Tabs from '../components/Tabs/Tabs'; import { WATCH_MEMBER, UNWATCH_MEMBER } from '../sagas/event'; class Server extends Component { diff --git a/frontend/src/containers/servers.js b/frontend/src/containers/servers.js index 2c4f4550..a798c342 100644 --- a/frontend/src/containers/servers.js +++ b/frontend/src/containers/servers.js @@ -1,7 +1,7 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; -import NomadLink from '../components/link'; -import FormatBoolean from '../components/format/boolean'; +import NomadLink from '../components/NomadLink/NomadLink'; +import FormatBoolean from '../components/FormatBoolean/FormatBoolean'; const Servers = ({ members }) => { return ( diff --git a/frontend/src/containers/statistics.js b/frontend/src/containers/statistics.js index 03732094..e35f3d57 100644 --- a/frontend/src/containers/statistics.js +++ b/frontend/src/containers/statistics.js @@ -1,6 +1,6 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; -import Progressbar from '../components/charts/progressbar'; +import Progressbar from '../components/Progressbar/Progressbar'; const Statistics = ({ jobs }) => { const clientStatus = { diff --git a/frontend/src/helpers/render/allocation.js b/frontend/src/helpers/render/allocation.js deleted file mode 100644 index d822f9b2..00000000 --- a/frontend/src/helpers/render/allocation.js +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react'; -import ReactTooltip from 'react-tooltip'; -import { Glyphicon } from 'react-bootstrap'; - -const clientStatusIcon = { - complete: , - running: , - lost: , - failed: , -}; - -export function renderDesiredStatus(allocation) { - if (allocation.DesiredDescription) { - return ( -
    - {allocation.DesiredDescription} - - {allocation.DesiredStatus} - -
    - ); - } - - return
    {allocation.DesiredStatus}
    ; -} - -export function renderClientStatus(allocation) { - let icon = null; - - if (allocation.ClientStatus in clientStatusIcon) { - icon = clientStatusIcon[allocation.ClientStatus]; - } - - return ( -
    - {allocation.ClientStatus} - {icon} -
    - ); -} diff --git a/frontend/src/helpers/statistics.js b/frontend/src/helpers/statistics.js deleted file mode 100644 index 2bb37fbb..00000000 --- a/frontend/src/helpers/statistics.js +++ /dev/null @@ -1,45 +0,0 @@ -import React from 'react'; - -const summaryLabels = ['Starting', 'Running', 'Queued', 'Complete', 'Failed', 'Lost']; - -export function getJobStatisticsHeader() { - const output = []; - - summaryLabels.forEach((key) => { - output.push({ key }); - }); - - return output; -} - -export function getJobStatisticsRow(job) { - const counter = { - Queued: 0, - Complete: 0, - Failed: 0, - Running: 0, - Starting: 0, - Lost: 0, - }; - - if (job.JobSummary !== null) { - const summary = job.JobSummary.Summary; - Object.keys(summary).forEach((taskGroupID) => { - counter.Queued += summary[taskGroupID].Queued; - counter.Complete += summary[taskGroupID].Complete; - counter.Failed += summary[taskGroupID].Failed; - counter.Running += summary[taskGroupID].Running; - counter.Starting += summary[taskGroupID].Starting; - counter.Lost += summary[taskGroupID].Lost; - }); - } else { - Object.keys(counter).forEach(key => (counter[key] = 'N/A')); - } - - const output = []; - summaryLabels.forEach((key) => { - output.push({counter[key]}); - }); - - return output; -} diff --git a/frontend/src/helpers/uuid.js b/frontend/src/helpers/uuid.js index d763c0a1..f6a287c4 100644 --- a/frontend/src/helpers/uuid.js +++ b/frontend/src/helpers/uuid.js @@ -1,11 +1,5 @@ function shortUUID(ID) { - const re = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; - - if (ID.match(re)) { - return ID.substring(0, 8); - } - - return ID; + return ID.substring(0, 8); } export default shortUUID; diff --git a/frontend/src/router.js b/frontend/src/router.js index e7c67590..b8303464 100644 --- a/frontend/src/router.js +++ b/frontend/src/router.js @@ -6,36 +6,36 @@ import Cluster from './containers/cluster'; import Jobs from './containers/jobs'; import Job from './containers/job'; -import JobInfo from './components/job/info'; -import JobAllocs from './components/job/allocs'; -import JobEvals from './components/job/evals'; -import JobTasks from './components/job/tasks'; -import JobTaskGroups from './components/job/taskGroups'; -import JobRaw from './components/job/raw'; +import JobInfo from './components/JobInfo/JobInfo'; +import JobAllocs from './components/JobAllocations/JobAllocations'; +import JobEvals from './components/JobEvaluations/JobEvaluations'; +import JobTasks from './components/JobTasks/JobTasks'; +import JobTaskGroups from './components/JobTaskGroups/JobTaskGroups'; +import JobRaw from './components/JobRaw/JobRaw'; import Allocations from './containers/allocations'; import Allocation from './containers/allocation'; -import AllocInfo from './components/allocation/info'; -import AllocFiles from './components/allocation/files'; -import AllocRaw from './components/allocation/raw'; +import AllocInfo from './components/AllocationInfo/AllocationInfo'; +import AllocFiles from './components/AllocationFiles/AllocationFiles'; +import AllocRaw from './components/AllocationRaw/AllocationRaw'; import Evaluations from './containers/evaluations'; import Evaluation from './containers/evaluation'; -import EvalInfo from './components/evaluation/info'; -import EvalAlloc from './components/evaluation/allocs'; -import EvalRaw from './components/evaluation/raw'; +import EvalInfo from './components/EvaluationInfo/EvaluationInfo'; +import EvalAllocations from './components/EvaluationAllocations/EvaluationAllocations'; +import EvalRaw from './components/EvaluationRaw/EvaluationRaw'; import Clients from './containers/clients'; import Client from './containers/client'; -import ClientInfo from './components/client/info'; -import ClientAllocations from './components/client/allocations'; -import ClientEvaluations from './components/client/evaluations'; -import ClientRaw from './components/client/raw'; +import ClientInfo from './components/ClientInfo/ClientInfo'; +import ClientAllocations from './components/ClientAllocations/ClientAllocations'; +import ClientEvaluations from './components/ClientEvaluations/ClientEvaluations'; +import ClientRaw from './components/ClientRaw/ClientRaw'; import Servers from './containers/servers'; import Server from './containers/server'; -import ServerInfo from './components/server/info'; -import ServerRaw from './components/server/raw'; +import ServerInfo from './components/ServerInfo/ServerInfo'; +import ServerRaw from './components/ServerRaw/ServerRaw'; const AppRouter = ({ history }) => @@ -87,7 +87,7 @@ const AppRouter = ({ history }) => - + From 1098ccea4558b2ed8ceed55afbe1ff7a0a5f714a Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 2 Dec 2016 14:40:16 +0100 Subject: [PATCH 02/45] fixes #151 --- frontend/src/components/AllocationList/AllocationList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/AllocationList/AllocationList.js b/frontend/src/components/AllocationList/AllocationList.js index e3623739..6423c185 100644 --- a/frontend/src/components/AllocationList/AllocationList.js +++ b/frontend/src/components/AllocationList/AllocationList.js @@ -268,7 +268,7 @@ class AllocationList extends Component { >
  • - Allocation { shortUUID(allocation.EvalID) } + Evaluation { shortUUID(allocation.EvalID) }
  • From eef370a4c883ba4d2b1c548172d8665f803b399f Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 2 Dec 2016 14:43:12 +0100 Subject: [PATCH 03/45] add editorconfig and fix forced indentation --- frontend/.editorconfig | 10 ++++++++++ frontend/.eslintrc.js | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 frontend/.editorconfig diff --git a/frontend/.editorconfig b/frontend/.editorconfig new file mode 100644 index 00000000..0f099897 --- /dev/null +++ b/frontend/.editorconfig @@ -0,0 +1,10 @@ +# editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js index b1a1f588..a3adc773 100644 --- a/frontend/.eslintrc.js +++ b/frontend/.eslintrc.js @@ -5,7 +5,7 @@ module.exports = { }, "extends": "airbnb", "rules": { - 'indent': ['error', 4], + 'indent': ['error', 2], 'no-constant-condition': ['error', { checkLoops: false }], 'no-console': 0, 'no-plusplus': 0, From 11032494b57ea0a73052e0949aa9eab5d4ef2732 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 2 Dec 2016 14:46:29 +0100 Subject: [PATCH 04/45] auto-fix eslint errors --- .../AllocationFiles/AllocationFiles.js | 451 +++++++++--------- .../AllocationInfo/AllocationInfo.js | 190 ++++---- .../AllocationList/AllocationList.js | 446 ++++++++--------- .../components/AllocationRaw/AllocationRaw.js | 4 +- .../ClientAllocations/ClientAllocations.js | 42 +- .../ClientEvaluations/ClientEvaluations.js | 28 +- .../src/components/ClientInfo/ClientInfo.js | 32 +- .../src/components/ClientRaw/ClientRaw.js | 4 +- .../components/ConstraintRow/ConstraintRow.js | 26 +- .../ConstraintTable/ConstraintTable.js | 84 ++-- .../EvaluationAllocations.js | 16 +- .../EvaluationInfo/EvaluationInfo.js | 16 +- .../EvaluationList/EvaluationList.js | 8 +- .../components/EvaluationRaw/EvaluationRaw.js | 4 +- .../components/FormatBoolean/FormatBoolean.js | 66 +-- .../src/components/FormatTime/FormatTime.js | 82 ++-- .../JobAllocations/JobAllocations.js | 48 +- .../JobEvaluations/JobEvaluations.js | 30 +- frontend/src/components/JobInfo/JobInfo.js | 218 ++++----- frontend/src/components/JobRaw/JobRaw.js | 4 +- .../components/JobTaskGroups/JobTaskGroups.js | 80 ++-- frontend/src/components/JobTasks/JobTasks.js | 124 ++--- .../src/components/MetaPayload/MetaPayload.js | 92 ++-- .../src/components/NodeStatus/NodeStatus.js | 24 +- .../src/components/NomadLink/NomadLink.js | 264 +++++----- .../src/components/Progressbar/Progressbar.js | 118 ++--- frontend/src/components/RawJson/RawJson.js | 50 +- .../src/components/ServerInfo/ServerInfo.js | 70 +-- .../src/components/ServerRaw/ServerRaw.js | 4 +- frontend/src/components/Sidebar/Sidebar.js | 124 ++--- frontend/src/components/Table/Table.js | 6 +- frontend/src/components/Tabs/Tabs.js | 8 +- frontend/src/components/Topbar/Topbar.js | 52 +- frontend/src/components/app.js | 30 +- frontend/src/containers/allocation.js | 122 ++--- frontend/src/containers/allocations.js | 40 +- frontend/src/containers/client.js | 122 ++--- frontend/src/containers/clients.js | 4 +- frontend/src/containers/cluster.js | 124 ++--- frontend/src/containers/evaluation.js | 114 ++--- frontend/src/containers/evaluations.js | 6 +- frontend/src/containers/events.js | 100 ++-- frontend/src/containers/job.js | 138 +++--- frontend/src/containers/jobs.js | 264 +++++----- frontend/src/containers/server.js | 106 ++-- frontend/src/containers/servers.js | 92 ++-- frontend/src/containers/statistics.js | 60 +-- frontend/src/helpers/time.js | 18 +- frontend/src/helpers/uuid.js | 2 +- frontend/src/main.js | 10 +- frontend/src/reducers/allocation.js | 34 +- frontend/src/reducers/evaluation.js | 24 +- frontend/src/reducers/filesystem.js | 32 +- frontend/src/reducers/job.js | 44 +- frontend/src/reducers/member.js | 24 +- frontend/src/reducers/node.js | 24 +- frontend/src/reducers/root.js | 24 +- frontend/src/router.js | 2 +- frontend/src/sagas/event.js | 136 +++--- frontend/src/store.js | 34 +- 60 files changed, 2273 insertions(+), 2272 deletions(-) diff --git a/frontend/src/components/AllocationFiles/AllocationFiles.js b/frontend/src/components/AllocationFiles/AllocationFiles.js index 09b037d1..d3c974ab 100644 --- a/frontend/src/components/AllocationFiles/AllocationFiles.js +++ b/frontend/src/components/AllocationFiles/AllocationFiles.js @@ -14,293 +14,294 @@ import { class AllocationFiles extends Component { - constructor(props) { - super(props); + constructor(props) { + super(props); // if the alloc node already in props // this only happens when you switch tab in the ui, this will never // trigger if /allocations/:id/files are the directly url and first page // you view - if (this.findAllocNode(props)) { - this.fetchDir(props, props.location.query.path || '/'); - } + if (this.findAllocNode(props)) { + this.fetchDir(props, props.location.query.path || '/'); + } // push our initial state - this.state = { - contents: '', - fileWatching: false, - initialDirectoryFetched: false, - }; + this.state = { + contents: '', + fileWatching: false, + initialDirectoryFetched: false, + }; + } + + componentWillReceiveProps(nextProps) { + if (!this.findAllocNode(nextProps)) { + return; + } + + let stateHaveChanged = false; + const nextState = this.state; + + const nextPath = nextProps.location.query.path; + const currentPath = this.props.location.query.path; + + const nextFile = nextProps.location.query.file; + const currentFile = this.props.location.query.file; + + if (currentPath !== nextPath || !this.state.initialDirectoryFetched) { + this.fetchDir(nextProps, nextPath); + nextState.initialDirectoryFetched = true; + stateHaveChanged = true; + } + + if (this.state.fileWatching && currentFile && currentFile !== nextFile) { + this.unwatchFile(nextProps, currentFile); + nextState.contents = ''; + nextState.fileWatching = false; + stateHaveChanged = true; } - componentWillReceiveProps(nextProps) { - if (!this.findAllocNode(nextProps)) { - return; - } - - let stateHaveChanged = false; - const nextState = this.state; - - const nextPath = nextProps.location.query.path; - const currentPath = this.props.location.query.path; - - const nextFile = nextProps.location.query.file; - const currentFile = this.props.location.query.file; - - if (currentPath !== nextPath || !this.state.initialDirectoryFetched) { - this.fetchDir(nextProps, nextPath); - nextState.initialDirectoryFetched = true; - stateHaveChanged = true; - } - - if (this.state.fileWatching && currentFile && currentFile !== nextFile) { - this.unwatchFile(nextProps, currentFile); - nextState.contents = ''; - nextState.fileWatching = false; - stateHaveChanged = true; - } - - if (!this.state.fileWatching && nextFile) { - this.watchFile(nextProps); - nextState.fileWatching = true; - stateHaveChanged = true; - } - - if (this.state.fileWatching && nextProps.file.Data) { - nextState.contents = this.state.contents + nextProps.file.Data; - stateHaveChanged = true; - - this.props.dispatch({ - type: CLEAR_RECEIVED_FILE_DATA, - payload: { - File: nextProps.file.File, - }, - }); - } - - if (stateHaveChanged) { - this.setState(nextState); - } + if (!this.state.fileWatching && nextFile) { + this.watchFile(nextProps); + nextState.fileWatching = true; + stateHaveChanged = true; } - componentWillUpdate() { - this.shouldScroll = (this.content.scrollTop + this.content.offsetHeight) === this.content.scrollHeight; + if (this.state.fileWatching && nextProps.file.Data) { + nextState.contents = this.state.contents + nextProps.file.Data; + stateHaveChanged = true; + + this.props.dispatch({ + type: CLEAR_RECEIVED_FILE_DATA, + payload: { + File: nextProps.file.File, + }, + }); } - componentDidUpdate() { - if (this.shouldScroll) { - this.content.scrollTop = this.content.scrollHeight; - } + if (stateHaveChanged) { + this.setState(nextState); } + } - componentWillUnmount() { - this.props.dispatch({ - type: CLEAR_FILE_PATH, - }); + componentWillUpdate() { + this.shouldScroll = (this.content.scrollTop + this.content.offsetHeight) === this.content.scrollHeight; + } - if (!this.state.fileWatching || !this.props.location.query.file) { - return; - } + componentDidUpdate() { + if (this.shouldScroll) { + this.content.scrollTop = this.content.scrollHeight; + } + } - this.unwatchFile(this.props, this.props.location.query.file); + componentWillUnmount() { + this.props.dispatch({ + type: CLEAR_FILE_PATH, + }); - this.setState({ - contents: '', - fileWatching: false, - initialDirectoryFetched: false, - }); + if (!this.state.fileWatching || !this.props.location.query.file) { + return; } - findAllocNode(props) { + this.unwatchFile(this.props, this.props.location.query.file); + + this.setState({ + contents: '', + fileWatching: false, + initialDirectoryFetched: false, + }); + } + + findAllocNode(props) { // Find the node that this alloc belongs to - const allocNode = props.nodes.find(node => node.ID === props.allocation.NodeID); + const allocNode = props.nodes.find(node => node.ID === props.allocation.NodeID); // No node for this alloc, so bail out - if (allocNode === undefined) { - return false; - } + if (allocNode === undefined) { + return false; + } // Fetch the correct node information if the alloc node changed - if (props.node == null || allocNode.ID !== props.node.ID) { - this.props.dispatch({ - type: FETCH_NODE, - payload: allocNode.ID, - }); + if (props.node == null || allocNode.ID !== props.node.ID) { + this.props.dispatch({ + type: FETCH_NODE, + payload: allocNode.ID, + }); - return false; - } + return false; + } // We've located the alloc node so go ahead and query the filesystem - return true; + return true; + } + + fetchDir(props, dir) { + this.props.dispatch({ + type: FETCH_DIR, + payload: { + addr: props.node.HTTPAddr, + path: dir || '/', + allocID: props.allocation.ID, + }, + }); + } + + watchFile(props) { + if (!this.findAllocNode(props)) { + return; } - fetchDir(props, dir) { - this.props.dispatch({ - type: FETCH_DIR, - payload: { - addr: props.node.HTTPAddr, - path: dir || '/', - allocID: props.allocation.ID, - }, - }); + const filePath = props.location.query.path + props.location.query.file; + + this.props.dispatch({ + type: WATCH_FILE, + payload: { + addr: props.node.HTTPAddr, + path: filePath, + allocID: props.allocation.ID, + }, + }); + } + + unwatchFile(props, file) { + if (!this.findAllocNode(props)) { + return; } - watchFile(props) { - if (!this.findAllocNode(props)) { - return; - } - - const filePath = props.location.query.path + props.location.query.file; - - this.props.dispatch({ - type: WATCH_FILE, - payload: { - addr: props.node.HTTPAddr, - path: filePath, - allocID: props.allocation.ID, - }, - }); + props.dispatch({ + type: UNWATCH_FILE, + payload: file, + }); + } + + handleClick(file) { + let path = this.props.location.query.path || '/'; + + if (file.IsDir) { + if (file.Name === 'back') { + path = path.substr(0, path.lastIndexOf('/', path.length - 2) + 1); + } else { + path = `${path}${file.Name}/`; + } + + this.props.history.push({ + pathname: this.props.location.pathname, + query: { path }, + }); + return; } - unwatchFile(props, file) { - if (!this.findAllocNode(props)) { - return; - } + this.props.history.push({ + pathname: this.props.location.pathname, + query: { + path, + file: file.Name, + }, + }); + } + + collectFiles() { + const files = this.props.directory.map(file => + this.handleClick(file) } key={ file.Name }> + { file.Name }{ file.IsDir ? '/' : '' } + { file.IsDir ? '' : file.Size } + + ); - props.dispatch({ - type: UNWATCH_FILE, - payload: file, - }); + if ((this.props.location.query.path || '/') !== '/') { + files.unshift( + this.handleClick({ Name: 'back', IsDir: true }) } key="back"> + .. + + + ); } - handleClick(file) { - let path = this.props.location.query.path || '/'; - - if (file.IsDir) { - if (file.Name === 'back') { - path = path.substr(0, path.lastIndexOf('/', path.length - 2) + 1); - } else { - path = `${path}${file.Name}/`; - } - - this.props.history.push({ - pathname: this.props.location.pathname, - query: { path }, - }); - return; - } - - this.props.history.push({ - pathname: this.props.location.pathname, - query: { - path, - file: file.Name, - }, - }); - } + return files; + } - collectFiles() { - const files = this.props.directory.map(file => - this.handleClick(file) } key={ file.Name }> - { file.Name }{ file.IsDir ? '/' : '' } - { file.IsDir ? '' : file.Size } - - ); + render() { + let hostname; + let fileName; - if ((this.props.location.query.path || '/') !== '/') { - files.unshift( - this.handleClick({ Name: 'back', IsDir: true }) } key="back"> - .. - - - ); - } + if (process.env.NODE_ENV === 'production') { + hostname = location.host; + } else { + hostname = `${location.hostname}:${process.env.GO_PORT}` || 3000; + } - return files; + if (this.state.fileWatching && this.props.file.File) { + fileName = this.props.file.File; + } else { + fileName = ''; } - render() { - let hostname; - let fileName; - - if (process.env.NODE_ENV === 'production') { - hostname = location.host; - } else { - hostname = `${location.hostname}:${process.env.GO_PORT}` || 3000; - } - - if (this.state.fileWatching && this.props.file.File) { - fileName = this.props.file.File; - } else { - fileName = ''; - } - - const oversizedWarning = !this.props.file.Oversized ? '' : - - - - - + const oversizedWarning = !this.props.file.Oversized ? '' : ( + + + + + The file you are trying to view is too large.
    Tailing has started from the last 250 lines.
    Please download the file for the entire contents.
    -
    -
    -
    ; +
    +
    +
    + ); - const baseUrl = `${location.protocol}//${hostname}`; - const downloadPath = `download${this.props.file.File}`; + const baseUrl = `${location.protocol}//${hostname}`; + const downloadPath = `download${this.props.file.File}`; - const downloadBtn = this.props.file.File ? '' : -
    + const downloadBtn = this.props.file.File ? '' : + ( { oversizedWarning } -
    ; - - return ( -
    -
    -
    -
    -
    Path: { this.props.location.query.path || '/' }
    -
    - - - + ); + + return ( +
    +
    +
    +
    +
    Path: { this.props.location.query.path || '/' }
    +
    +
    -
    -
    -
    File: { fileName } - { downloadBtn } -
    - -
    -
    { this.content = c; } }> - { this.state.contents } -
    -
    +
    + +
    +
    +
    File: { fileName } + { downloadBtn } +
    + +
    +
    { this.content = c; } }> + { this.state.contents }
    - ); - } + + + ); + } } function mapStateToProps({ allocation, nodes, node, directory, file }) { - return { allocation, nodes, node, directory, file }; + return { allocation, nodes, node, directory, file }; } AllocationFiles.propTypes = { - node: PropTypes.object.isRequired, - location: PropTypes.object.isRequired, - allocation: PropTypes.object.isRequired, - dispatch: PropTypes.func.isRequired, - file: PropTypes.object.isRequired, - directory: PropTypes.array.isRequired, - history: PropTypes.object.isRequired, + node: PropTypes.object.isRequired, + location: PropTypes.object.isRequired, + allocation: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired, + file: PropTypes.object.isRequired, + directory: PropTypes.array.isRequired, + history: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(AllocationFiles); diff --git a/frontend/src/components/AllocationInfo/AllocationInfo.js b/frontend/src/components/AllocationInfo/AllocationInfo.js index d334d200..682a9c84 100644 --- a/frontend/src/components/AllocationInfo/AllocationInfo.js +++ b/frontend/src/components/AllocationInfo/AllocationInfo.js @@ -6,58 +6,58 @@ import MetaPayload from '../MetaPayload/MetaPayload'; import FormatTime from '../FormatTime/FormatTime'; const allocProps = [ - 'ID', - 'Name', - 'ClientStatus', - 'ClientDescription', - 'DesiredStatus', - 'DesiredDescription', + 'ID', + 'Name', + 'ClientStatus', + 'ClientDescription', + 'DesiredStatus', + 'DesiredDescription', ]; class AllocationInfo extends Component { - static taskState(allocation, name, states) { - const title = ( -

    + static taskState(allocation, name, states) { + const title = ( +

    Task state for {allocation.JobID}.{allocation.TaskGroup}.{name} (final state: {states.State})

    ); - let lastEventTime = null; + let lastEventTime = null; - return ( - -
    -
    - - - - - - - - - - - - { states.Events.map((element, index) => { - if (!lastEventTime) { - lastEventTime = element.Time; - } + return ( + +
    +
    WhenDurationTypeMessage / ReasonSignalCode
    + + + + + + + + + + + + { states.Events.map((element, index) => { + if (!lastEventTime) { + lastEventTime = element.Time; + } - const output = ( - - - - - + + + + - - - + + + + ); - lastEventTime = element.Time; - return output; - })} - -
    WhenDurationTypeMessage / ReasonSignalCode
    - - { element.Type } - { + const output = ( +
    + + { element.Type } + { element.Message || element.SetupError || element.DriverError @@ -69,73 +69,73 @@ class AllocationInfo extends Component { || element.KillReason || element.TaskSignalReason } - { element.Signal || element.TaskSignal }{ element.ExitCode }
    { element.Signal || element.TaskSignal }{ element.ExitCode }
    -
    - - ); - } + lastEventTime = element.Time; + return output; + })} + + +
    + + ); + } - render() { - const allocation = this.props.allocation; - const jobId = allocation.JobID; - const nodeId = allocation.NodeID; - const taskGroupId = allocation.TaskGroupId; + render() { + const allocation = this.props.allocation; + const jobId = allocation.JobID; + const nodeId = allocation.NodeID; + const taskGroupId = allocation.TaskGroupId; - const allocValues = {}; - allocProps.map((allocProp) => { - allocValues[allocProp] = allocation[allocProp]; - return null; - }); + const allocValues = {}; + allocProps.map((allocProp) => { + allocValues[allocProp] = allocation[allocProp]; + return null; + }); - allocValues.Job = ; - allocValues.TaskGroup = ( - - {allocation.TaskGroup} - + allocValues.Job = ; + allocValues.TaskGroup = ( + + {allocation.TaskGroup} + ); - allocValues.Node = ; + allocValues.Node = ; - const states = []; - Object.keys(allocation.TaskStates || {}).forEach((key) => { - states.push(AllocationInfo.taskState(allocation, key, allocation.TaskStates[key])); - }); + const states = []; + Object.keys(allocation.TaskStates || {}).forEach((key) => { + states.push(AllocationInfo.taskState(allocation, key, allocation.TaskStates[key])); + }); - return ( -
    -
    -
    - Allocation Properties - -
    -
    -
    -
    - Task States - { states } -
    -
    + return ( +
    +
    +
    + Allocation Properties +
    - ); - } +
    +
    +
    + Task States + { states } +
    +
    +
    + ); + } } function mapStateToProps({ allocation, nodes }) { - return { allocation, nodes }; + return { allocation, nodes }; } AllocationInfo.propTypes = { - allocation: PropTypes.object.isRequired, - nodes: PropTypes.array.isRequired, + allocation: PropTypes.object.isRequired, + nodes: PropTypes.array.isRequired, }; export default connect(mapStateToProps)(AllocationInfo); diff --git a/frontend/src/components/AllocationList/AllocationList.js b/frontend/src/components/AllocationList/AllocationList.js index 6423c185..3bdac2cf 100644 --- a/frontend/src/components/AllocationList/AllocationList.js +++ b/frontend/src/components/AllocationList/AllocationList.js @@ -1,316 +1,316 @@ import React, { Component, PropTypes } from 'react'; import { DropdownButton, Glyphicon } from 'react-bootstrap'; import { Link } from 'react-router'; +import ReactTooltip from 'react-tooltip'; import NomadLink from '../NomadLink/NomadLink'; import FormatTime from '../FormatTime/FormatTime'; import shortUUID from '../../helpers/uuid'; -import ReactTooltip from 'react-tooltip'; const getAllocationNumberFromName = (allocationName) => { - const match = /[\d+]/.exec(allocationName); - return match[0]; + const match = /[\d+]/.exec(allocationName); + return match[0]; }; const clientStatusIcon = { - complete: , - running: , - lost: , - failed: , + complete: , + running: , + lost: , + failed: , }; const optionsGlyph = ; const jobHeaderColumn = display => - (display ? Job : null); + (display ? Job : null); const jobColumn = (allocation, display) => - (display ? : null); + (display ? : null); const clientHeaderColumn = display => - (display ? Client : null); + (display ? Client : null); const clientColumn = (allocation, nodes, display) => - (display ? : null); + (display ? : null); const renderDesiredStatus = (allocation) => { - if (allocation.DesiredDescription) { - return ( -
    - {allocation.DesiredDescription} - - {allocation.DesiredStatus} - -
    - ); - } - - return
    {allocation.DesiredStatus}
    ; -} - -const renderClientStatus = (allocation) => { - let icon = null; - - if (allocation.ClientStatus in clientStatusIcon) { - icon = clientStatusIcon[allocation.ClientStatus]; - } - + if (allocation.DesiredDescription) { return (
    - {allocation.ClientStatus} - {icon} + {allocation.DesiredDescription} + + {allocation.DesiredStatus} +
    ); -} + } + + return
    {allocation.DesiredStatus}
    ; +}; + +const renderClientStatus = (allocation) => { + let icon = null; + + if (allocation.ClientStatus in clientStatusIcon) { + icon = clientStatusIcon[allocation.ClientStatus]; + } + + return ( +
    + {allocation.ClientStatus} + {icon} +
    + ); +}; let nodeIdToNameCache = {}; class AllocationList extends Component { - componentWillReceiveProps(nextProps) { - if (nextProps.nodes !== this.props.nodes) { - nodeIdToNameCache = {}; - } + componentWillReceiveProps(nextProps) { + if (nextProps.nodes !== this.props.nodes) { + nodeIdToNameCache = {}; } + } - findNodeNameById(nodeId) { - if (nodeId in nodeIdToNameCache) { - return nodeIdToNameCache[nodeId]; - } + findNodeNameById(nodeId) { + if (nodeId in nodeIdToNameCache) { + return nodeIdToNameCache[nodeId]; + } - const r = Object.keys(this.props.nodes) + const r = Object.keys(this.props.nodes) .filter(node => this.props.nodes[node].ID === nodeId ); - if (r.length !== 0) { - nodeIdToNameCache[nodeId] = this.props.nodes[r].Name; - } else { - nodeIdToNameCache[nodeId] = nodeId; - } - - return nodeIdToNameCache[nodeId]; + if (r.length !== 0) { + nodeIdToNameCache[nodeId] = this.props.nodes[r].Name; + } else { + nodeIdToNameCache[nodeId] = nodeId; } - filteredAllocations() { - const query = this.props.location.query || {}; - let allocations = this.props.allocations; + return nodeIdToNameCache[nodeId]; + } - if ('status' in query) { - allocations = allocations.filter(allocation => allocation.ClientStatus === query.status); - } + filteredAllocations() { + const query = this.props.location.query || {}; + let allocations = this.props.allocations; - if ('client' in query) { - allocations = allocations.filter(allocation => allocation.NodeID === query.client); - } + if ('status' in query) { + allocations = allocations.filter(allocation => allocation.ClientStatus === query.status); + } - if ('job' in query) { - allocations = allocations.filter(allocation => allocation.JobID === query.job); - } + if ('client' in query) { + allocations = allocations.filter(allocation => allocation.NodeID === query.client); + } - return allocations; + if ('job' in query) { + allocations = allocations.filter(allocation => allocation.JobID === query.job); } - clientStatusFilter() { - const location = this.props.location; - const query = this.props.location.query || {}; - - let title = 'Client Status'; - if ('status' in query) { - title = {title}: { query.status }; - } - - return ( - -
  • - Any -
  • -
  • Running
  • -
  • Complete
  • -
  • Pending
  • -
  • Lost
  • -
  • Failed
  • - - ); + return allocations; + } + + clientStatusFilter() { + const location = this.props.location; + const query = this.props.location.query || {}; + + let title = 'Client Status'; + if ('status' in query) { + title = {title}: { query.status }; } - jobIdFilter() { - const location = this.props.location; - const query = this.props.location.query || {}; + return ( + +
  • - Any -
  • +
  • Running
  • +
  • Complete
  • +
  • Pending
  • +
  • Lost
  • +
  • Failed
  • +
    + ); + } + + jobIdFilter() { + const location = this.props.location; + const query = this.props.location.query || {}; - let title = 'Job'; - if ('job' in query) { - title = {title}: { query.job }; - } + let title = 'Job'; + if ('job' in query) { + title = {title}: { query.job }; + } - const jobs = this.props.allocations + const jobs = this.props.allocations .map((allocation) => { - return allocation.JobID; + return allocation.JobID; }) .filter((v, i, a) => { - return a.indexOf(v) === i; + return a.indexOf(v) === i; }) .map((job) => { - return ( -
  • - { job } -
  • - ); + return ( +
  • + { job } +
  • + ); }); - jobs.unshift( -
  • - Any -
  • + jobs.unshift( +
  • - Any -
  • ); - return ( - - { jobs } - - ); - } + return ( + + { jobs } + + ); + } - clientFilter() { - const location = this.props.location; - const query = this.props.location.query || {}; + clientFilter() { + const location = this.props.location; + const query = this.props.location.query || {}; - let title = 'Client'; - if ('client' in query) { - title = {title}: { this.findNodeNameById(query.client) }; - } + let title = 'Client'; + if ('client' in query) { + title = {title}: { this.findNodeNameById(query.client) }; + } - const clients = this.props.allocations + const clients = this.props.allocations .map((allocation) => { - return allocation.NodeID; + return allocation.NodeID; }) .filter((v, i, a) => { - return a.indexOf(v) === i; + return a.indexOf(v) === i; }) .map((client) => { - return ( -
  • - { this.findNodeNameById(client) } -
  • - ); + return ( +
  • + { this.findNodeNameById(client) } +
  • + ); }); - clients.unshift( -
  • - - Any - -
  • + clients.unshift( +
  • + - Any - +
  • ); - return ( - - { clients } - - ); - } + return ( + + { clients } + + ); + } - render() { - const showJobColumn = this.props.showJobColumn; - const showClientColumn = this.props.showClientColumn; - const allocations = this.props.allocations; - const nodes = this.props.nodes; - const className = this.props.containerClassName; - - return ( -
    -
    - { this.clientFilter() } + render() { + const showJobColumn = this.props.showJobColumn; + const showClientColumn = this.props.showClientColumn; + const allocations = this.props.allocations; + const nodes = this.props.nodes; + const className = this.props.containerClassName; + + return ( +
    +
    + { this.clientFilter() }   - { this.clientStatusFilter() } + { this.clientStatusFilter() }   - { this.jobIdFilter() } -
    -
    - - - - - - { jobHeaderColumn(showJobColumn) } - - - { clientHeaderColumn(showClientColumn) } - - - - - - {this.filteredAllocations().map((allocation, index) => { - return ( - - - - { jobColumn(allocation, showJobColumn, nodes) } - + + ); + })} + +
    IDTask GroupStatusAgeActions
    { renderClientStatus(allocation) } - - { allocation.TaskGroup } (#{ getAllocationNumberFromName(allocation.Name) }) + { this.jobIdFilter() } + +
    + + + + + + { jobHeaderColumn(showJobColumn) } + + + { clientHeaderColumn(showClientColumn) } + + + + + + {this.filteredAllocations().map((allocation, index) => { + return ( + + + + { jobColumn(allocation, showJobColumn, nodes) } + - - { clientColumn(allocation, nodes, showClientColumn) } - - + + { clientColumn(allocation, nodes, showClientColumn) } + + - - ); - })} - -
    IDTask GroupStatusAgeActions
    { renderClientStatus(allocation) } + + { allocation.TaskGroup } (#{ getAllocationNumberFromName(allocation.Name) }) - { renderDesiredStatus(allocation) } - - - - - allocations.length - 4 } - className="btn btn-xs btn-simple pull-right" - title={ optionsGlyph } - key={ allocation.Name } - id={ `actions-${allocation.Name}` } - > -
  • - +
  • { renderDesiredStatus(allocation) } + + + + + allocations.length - 4 } + className="btn btn-xs btn-simple pull-right" + title={ optionsGlyph } + key={ allocation.Name } + id={ `actions-${allocation.Name}` } + > +
  • + Evaluation { shortUUID(allocation.EvalID) } - -
  • -
  • - + +
  • +
  • + Files -
  • -
  • - Task States -
  • -
    -
    -
    - ); - } + +
  • + Task States +
  • + +
    +
    +
    ); + } } AllocationList.defaultProps = { - allocations: [], - nodes: [], - location: {}, + allocations: [], + nodes: [], + location: {}, - showJobColumn: true, - showClientColumn: true, + showJobColumn: true, + showClientColumn: true, - containerClassName: '', + containerClassName: '', }; AllocationList.propTypes = { - allocations: PropTypes.array.isRequired, - nodes: PropTypes.array.isRequired, - location: PropTypes.object.isRequired, + allocations: PropTypes.array.isRequired, + nodes: PropTypes.array.isRequired, + location: PropTypes.object.isRequired, - showJobColumn: PropTypes.bool.isRequired, - showClientColumn: PropTypes.bool.isRequired, + showJobColumn: PropTypes.bool.isRequired, + showClientColumn: PropTypes.bool.isRequired, - containerClassName: PropTypes.string.isRequired, + containerClassName: PropTypes.string.isRequired, }; export default AllocationList; diff --git a/frontend/src/components/AllocationRaw/AllocationRaw.js b/frontend/src/components/AllocationRaw/AllocationRaw.js index 70f688d4..b4b42f3f 100644 --- a/frontend/src/components/AllocationRaw/AllocationRaw.js +++ b/frontend/src/components/AllocationRaw/AllocationRaw.js @@ -9,11 +9,11 @@ const AllocationRaw = ({ allocation }) =>
    ; function mapStateToProps({ allocation }) { - return { allocation }; + return { allocation }; } AllocationRaw.propTypes = { - allocation: PropTypes.object.isRequired, + allocation: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(AllocationRaw); diff --git a/frontend/src/components/ClientAllocations/ClientAllocations.js b/frontend/src/components/ClientAllocations/ClientAllocations.js index c669a4cf..b013dfb1 100644 --- a/frontend/src/components/ClientAllocations/ClientAllocations.js +++ b/frontend/src/components/ClientAllocations/ClientAllocations.js @@ -4,37 +4,37 @@ import AllocationList from '../AllocationList/AllocationList'; class ClientAllocations extends PureComponent { - render() { - const nodeId = this.props.params.nodeId; - const allocs = this.props.allocations.filter(allocation => allocation.NodeID === nodeId); + render() { + const nodeId = this.props.params.nodeId; + const allocs = this.props.allocations.filter(allocation => allocation.NodeID === nodeId); - return ( -
    - -
    - ); - } + return ( +
    + +
    + ); + } } function mapStateToProps({ allocations }) { - return { allocations }; + return { allocations }; } ClientAllocations.defaultProps = { - allocations: [], - params: {}, - location: {}, + allocations: [], + params: {}, + location: {}, }; ClientAllocations.propTypes = { - allocations: PropTypes.array.isRequired, - params: PropTypes.object.isRequired, - location: PropTypes.object.isRequired, + allocations: PropTypes.array.isRequired, + params: PropTypes.object.isRequired, + location: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(ClientAllocations); diff --git a/frontend/src/components/ClientEvaluations/ClientEvaluations.js b/frontend/src/components/ClientEvaluations/ClientEvaluations.js index 64e1ed6d..a7ba7ba3 100644 --- a/frontend/src/components/ClientEvaluations/ClientEvaluations.js +++ b/frontend/src/components/ClientEvaluations/ClientEvaluations.js @@ -4,30 +4,30 @@ import EvaluationList from '../EvaluationList/EvaluationList'; class ClientEvaluations extends PureComponent { - render() { - const nodeId = this.props.params.nodeId; - const evals = this.props.evaluations.filter(evaluation => evaluation.NodeID === nodeId); + render() { + const nodeId = this.props.params.nodeId; + const evals = this.props.evaluations.filter(evaluation => evaluation.NodeID === nodeId); - return ( -
    - -
    - ); - } + return ( +
    + +
    + ); + } } function mapStateToProps({ evaluations }) { - return { evaluations }; + return { evaluations }; } ClientEvaluations.defaultProps = { - evaluations: [], - params: {}, + evaluations: [], + params: {}, }; ClientEvaluations.propTypes = { - evaluations: PropTypes.array.isRequired, - params: PropTypes.object.isRequired, + evaluations: PropTypes.array.isRequired, + params: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(ClientEvaluations); diff --git a/frontend/src/components/ClientInfo/ClientInfo.js b/frontend/src/components/ClientInfo/ClientInfo.js index 6afd85ac..34cacf19 100644 --- a/frontend/src/components/ClientInfo/ClientInfo.js +++ b/frontend/src/components/ClientInfo/ClientInfo.js @@ -3,25 +3,25 @@ import { connect } from 'react-redux'; import MetaPayload from '../MetaPayload/MetaPayload'; const nodeProps = [ - 'ID', - 'Name', - 'Status', - 'Datacenter', - 'Drain', - 'HTTPAddr', - 'NodeClass', + 'ID', + 'Name', + 'Status', + 'Datacenter', + 'Drain', + 'HTTPAddr', + 'NodeClass', ]; const withPrefix = function withPrefix(obj, prefix) { - const result = {}; + const result = {}; - Object.keys(obj || {}).forEach((key) => { - if (key.startsWith(prefix)) { - result[key.replace(prefix, '')] = obj[key]; - } - }); + Object.keys(obj || {}).forEach((key) => { + if (key.startsWith(prefix)) { + result[key.replace(prefix, '')] = obj[key]; + } + }); - return result; + return result; }; const ClientInfo = ({ node }) => @@ -68,11 +68,11 @@ const ClientInfo = ({ node }) =>
    ; function mapStateToProps({ node }) { - return { node }; + return { node }; } ClientInfo.propTypes = { - node: PropTypes.object.isRequired, + node: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(ClientInfo); diff --git a/frontend/src/components/ClientRaw/ClientRaw.js b/frontend/src/components/ClientRaw/ClientRaw.js index b263bf6a..1c6a7629 100644 --- a/frontend/src/components/ClientRaw/ClientRaw.js +++ b/frontend/src/components/ClientRaw/ClientRaw.js @@ -11,11 +11,11 @@ const ClientRaw = ({ node }) =>
    ; function mapStateToProps({ node }) { - return { node }; + return { node }; } ClientRaw.propTypes = { - node: PropTypes.object.isRequired, + node: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(ClientRaw); diff --git a/frontend/src/components/ConstraintRow/ConstraintRow.js b/frontend/src/components/ConstraintRow/ConstraintRow.js index 01ff5d4e..0c6a3f47 100644 --- a/frontend/src/components/ConstraintRow/ConstraintRow.js +++ b/frontend/src/components/ConstraintRow/ConstraintRow.js @@ -2,29 +2,29 @@ import React, { PropTypes } from 'react'; const ConstraintRow = ({ constraint }) => { // unique case as it does not expose any LTarget or RTarget - if (constraint.Operand === 'distinct_hosts') { - return ( - - Distinct Hosts - - ); - } - + if (constraint.Operand === 'distinct_hosts') { return ( - { constraint.LTarget } - { constraint.Operand } - { constraint.RTarget } + Distinct Hosts ); + } + + return ( + + { constraint.LTarget } + { constraint.Operand } + { constraint.RTarget } + + ); }; ConstraintRow.defaultProps = { - constraint: {}, + constraint: {}, }; ConstraintRow.propTypes = { - constraint: PropTypes.object.isRequired, + constraint: PropTypes.object.isRequired, }; export default ConstraintRow; diff --git a/frontend/src/components/ConstraintTable/ConstraintTable.js b/frontend/src/components/ConstraintTable/ConstraintTable.js index e860ad27..7ae5140f 100644 --- a/frontend/src/components/ConstraintTable/ConstraintTable.js +++ b/frontend/src/components/ConstraintTable/ConstraintTable.js @@ -4,61 +4,61 @@ import ConstraintRow from '../ConstraintRow/ConstraintRow'; class ConstraintTable extends Component { - render() { - function getUniqueKeyForConstraint(constraint) { - return (`${constraint.LTarget}@${constraint.RTarget}@${constraint.Operand}`); - } + render() { + function getUniqueKeyForConstraint(constraint) { + return (`${constraint.LTarget}@${constraint.RTarget}@${constraint.Operand}`); + } - if (this.props.constraints === null || this.props.constraints.length === 0) { - return -; - } + if (this.props.constraints === null || this.props.constraints.length === 0) { + return -; + } - const table = ( - - - - - - - - - - { this.props.constraints.map(constraint => - + const table = ( +
    KeyOperandValue
    + + + + + + + + + { this.props.constraints.map(constraint => + )} - -
    KeyOperandValue
    + + ); - if (this.props.asTooltip) { - return ( -
    - { table } - - { this.props.constraints.length } constraints + if (this.props.asTooltip) { + return ( +
    + { table } + + { this.props.constraints.length } constraints -
    - ); - } - - return table; +
    + ); } + + return table; + } } ConstraintTable.defaultProps = { - constraints: [], - asTooltip: false, - idPrefix: null, + constraints: [], + asTooltip: false, + idPrefix: null, }; ConstraintTable.propTypes = { - constraints: PropTypes.array, - idPrefix: PropTypes.string, - asTooltip: PropTypes.bool.isRequired, + constraints: PropTypes.array, + idPrefix: PropTypes.string, + asTooltip: PropTypes.bool.isRequired, }; export default ConstraintTable; diff --git a/frontend/src/components/EvaluationAllocations/EvaluationAllocations.js b/frontend/src/components/EvaluationAllocations/EvaluationAllocations.js index 2e3161ee..d040459d 100644 --- a/frontend/src/components/EvaluationAllocations/EvaluationAllocations.js +++ b/frontend/src/components/EvaluationAllocations/EvaluationAllocations.js @@ -3,21 +3,21 @@ import { connect } from 'react-redux'; import AllocationList from '../AllocationList/AllocationList'; const EvaluationAllocations = ({ allocations, evaluation, nodes }) => { - const allocs = allocations.filter(allocation => allocation.EvalID === evaluation.ID); + const allocs = allocations.filter(allocation => allocation.EvalID === evaluation.ID); - return ( - - ); + return ( + + ); }; function mapStateToProps({ evaluation, allocations, nodes }) { - return { evaluation, allocations, nodes }; + return { evaluation, allocations, nodes }; } EvaluationAllocations.propTypes = { - allocations: PropTypes.array.isRequired, - evaluation: PropTypes.object.isRequired, - nodes: PropTypes.array.isRequired, + allocations: PropTypes.array.isRequired, + evaluation: PropTypes.object.isRequired, + nodes: PropTypes.array.isRequired, }; export default connect(mapStateToProps)(EvaluationAllocations); diff --git a/frontend/src/components/EvaluationInfo/EvaluationInfo.js b/frontend/src/components/EvaluationInfo/EvaluationInfo.js index 5db33cd1..de773b06 100644 --- a/frontend/src/components/EvaluationInfo/EvaluationInfo.js +++ b/frontend/src/components/EvaluationInfo/EvaluationInfo.js @@ -2,12 +2,12 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; const evaluationProps = [ - 'ID', - 'Status', - 'Priority', - 'Type', - 'JobID', - 'TriggeredBy', + 'ID', + 'Status', + 'Priority', + 'Type', + 'JobID', + 'TriggeredBy', ]; const EvaluationInfo = ({ evaluation }) => @@ -28,11 +28,11 @@ const EvaluationInfo = ({ evaluation }) =>
    ; function mapStateToProps({ evaluation }) { - return { evaluation }; + return { evaluation }; } EvaluationInfo.propTypes = { - evaluation: PropTypes.object.isRequired, + evaluation: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(EvaluationInfo); diff --git a/frontend/src/components/EvaluationList/EvaluationList.js b/frontend/src/components/EvaluationList/EvaluationList.js index bafac45f..e3ae0d43 100644 --- a/frontend/src/components/EvaluationList/EvaluationList.js +++ b/frontend/src/components/EvaluationList/EvaluationList.js @@ -36,13 +36,13 @@ const EvaluationList = ({ evaluations, containerClassName }) => ; EvaluationList.defaultProps = { - evaluations: [], - containerClassName: '', + evaluations: [], + containerClassName: '', }; EvaluationList.propTypes = { - evaluations: PropTypes.array.isRequired, - containerClassName: PropTypes.string.isRequired, + evaluations: PropTypes.array.isRequired, + containerClassName: PropTypes.string.isRequired, }; export default EvaluationList; diff --git a/frontend/src/components/EvaluationRaw/EvaluationRaw.js b/frontend/src/components/EvaluationRaw/EvaluationRaw.js index 774e617e..523a9ab4 100644 --- a/frontend/src/components/EvaluationRaw/EvaluationRaw.js +++ b/frontend/src/components/EvaluationRaw/EvaluationRaw.js @@ -9,11 +9,11 @@ const EvaluationRaw = ({ evaluation }) => ; function mapStateToProps({ evaluation }) { - return { evaluation }; + return { evaluation }; } EvaluationRaw.propTypes = { - evaluation: PropTypes.object.isRequired, + evaluation: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(EvaluationRaw); diff --git a/frontend/src/components/FormatBoolean/FormatBoolean.js b/frontend/src/components/FormatBoolean/FormatBoolean.js index 26ce5dc5..452e968a 100644 --- a/frontend/src/components/FormatBoolean/FormatBoolean.js +++ b/frontend/src/components/FormatBoolean/FormatBoolean.js @@ -12,55 +12,55 @@ const FormatBoolean = ({ falseIcon, trueIcon, }) => { - let colorClass; - let icon; - let text; + let colorClass; + let icon; + let text; - if (withColor) { - colorClass = value ? 'text-success' : 'text-danger'; - } + if (withColor) { + colorClass = value ? 'text-success' : 'text-danger'; + } - if (withIcon) { - icon = ; - } + if (withIcon) { + icon = ; + } - if (withText) { - text = { value ? trueText : falseText }; - } + if (withText) { + text = { value ? trueText : falseText }; + } - return ( - { icon } { text } - ); + return ( + { icon } { text } + ); }; FormatBoolean.defaultProps = { - value: null, - title: null, + value: null, + title: null, - withColor: true, - withIcon: true, - withText: false, + withColor: true, + withIcon: true, + withText: false, - trueText: 'yes', - trueIcon: 'ok', + trueText: 'yes', + trueIcon: 'ok', - falseText: 'no', - falseIcon: 'remove', + falseText: 'no', + falseIcon: 'remove', }; FormatBoolean.propTypes = { - value: PropTypes.bool.isRequired, - title: PropTypes.string, + value: PropTypes.bool.isRequired, + title: PropTypes.string, - withColor: PropTypes.bool.isRequired, - withIcon: PropTypes.bool.isRequired, - withText: PropTypes.bool.isRequired, + withColor: PropTypes.bool.isRequired, + withIcon: PropTypes.bool.isRequired, + withText: PropTypes.bool.isRequired, - trueText: PropTypes.string.isRequired, - trueIcon: PropTypes.string.isRequired, + trueText: PropTypes.string.isRequired, + trueIcon: PropTypes.string.isRequired, - falseText: PropTypes.string.isRequired, - falseIcon: PropTypes.string.isRequired, + falseText: PropTypes.string.isRequired, + falseIcon: PropTypes.string.isRequired, }; export default FormatBoolean; diff --git a/frontend/src/components/FormatTime/FormatTime.js b/frontend/src/components/FormatTime/FormatTime.js index 5d905fe3..90137ed0 100644 --- a/frontend/src/components/FormatTime/FormatTime.js +++ b/frontend/src/components/FormatTime/FormatTime.js @@ -8,61 +8,61 @@ import getMoment from '../../helpers/time'; class FormatTime extends Component { - getTimeDiff(time, now) { - if (this.props.durationInterval && this.props.durationFormat) { - return moment + getTimeDiff(time, now) { + if (this.props.durationInterval && this.props.durationFormat) { + return moment .duration(time.diff(now), this.props.durationInterval) .format(this.props.durationFormat, { forceLength: true }); - } - - return time.from(now, true); } - render() { - const time = getMoment(this.props.time); - const now = getMoment(this.props.now); - const format = this.props.timeFormat; - const uuidValue = uuid.v1(); + return time.from(now, true); + } - if (this.props.display === 'relative') { - return ( - - { time.format(format) } - - {this.getTimeDiff(time, now)} - - - ); - } + render() { + const time = getMoment(this.props.time); + const now = getMoment(this.props.now); + const format = this.props.timeFormat; + const uuidValue = uuid.v1(); - return ( - - { this.getTimeDiff(time, now) } - { time.format(format) } + if (this.props.display === 'relative') { + return ( + + { time.format(format) } + + {this.getTimeDiff(time, now)} - ); + + ); } + + return ( + + { this.getTimeDiff(time, now) } + { time.format(format) } + + ); + } } FormatTime.defaultProps = { - time: null, - now: 'now', - display: 'relative', - timeFormat: 'DD-MM-YYYY H:mm:ss', - durationInterval: null, - durationFormat: null, + time: null, + now: 'now', + display: 'relative', + timeFormat: 'DD-MM-YYYY H:mm:ss', + durationInterval: null, + durationFormat: null, }; FormatTime.propTypes = { - time: PropTypes.number.isRequired, - now: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.number, - ]), - display: PropTypes.string.isRequired, - timeFormat: PropTypes.string.isRequired, - durationInterval: PropTypes.string, - durationFormat: PropTypes.string, + time: PropTypes.number.isRequired, + now: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + ]), + display: PropTypes.string.isRequired, + timeFormat: PropTypes.string.isRequired, + durationInterval: PropTypes.string, + durationFormat: PropTypes.string, }; export default FormatTime; diff --git a/frontend/src/components/JobAllocations/JobAllocations.js b/frontend/src/components/JobAllocations/JobAllocations.js index c6e1c690..60ac2677 100644 --- a/frontend/src/components/JobAllocations/JobAllocations.js +++ b/frontend/src/components/JobAllocations/JobAllocations.js @@ -4,42 +4,42 @@ import AllocationList from '../AllocationList/AllocationList'; class JobAllocations extends PureComponent { - render() { - const jobId = this.props.params.jobId; - const allocs = this.props.allocations.filter(allocation => + render() { + const jobId = this.props.params.jobId; + const allocs = this.props.allocations.filter(allocation => allocation.JobID === jobId ); - return ( -
    - -
    - ); - } + return ( +
    + +
    + ); + } } function mapStateToProps({ allocations, nodes }) { - return { allocations, nodes }; + return { allocations, nodes }; } JobAllocations.defaultProps = { - allocations: [], - nodes: [], - params: {}, - location: {}, + allocations: [], + nodes: [], + params: {}, + location: {}, }; JobAllocations.propTypes = { - allocations: PropTypes.array.isRequired, - params: PropTypes.object.isRequired, - nodes: PropTypes.array.isRequired, - location: PropTypes.object.isRequired, + allocations: PropTypes.array.isRequired, + params: PropTypes.object.isRequired, + nodes: PropTypes.array.isRequired, + location: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(JobAllocations); diff --git a/frontend/src/components/JobEvaluations/JobEvaluations.js b/frontend/src/components/JobEvaluations/JobEvaluations.js index 31c10ddd..2be42d9f 100644 --- a/frontend/src/components/JobEvaluations/JobEvaluations.js +++ b/frontend/src/components/JobEvaluations/JobEvaluations.js @@ -4,30 +4,30 @@ import EvaluationList from '../EvaluationList/EvaluationList'; class JobEvaluations extends PureComponent { - render() { - const jobId = this.props.params.jobId; - const evals = this.props.evaluations.filter(evaluation => evaluation.JobID === jobId); - - return ( -
    - -
    - ); - } + render() { + const jobId = this.props.params.jobId; + const evals = this.props.evaluations.filter(evaluation => evaluation.JobID === jobId); + + return ( +
    + +
    + ); + } } function mapStateToProps({ evaluations }) { - return { evaluations }; + return { evaluations }; } JobEvaluations.defaultProps = { - evaluations: [], - params: {}, + evaluations: [], + params: {}, }; JobEvaluations.propTypes = { - evaluations: PropTypes.array.isRequired, - params: PropTypes.object.isRequired, + evaluations: PropTypes.array.isRequired, + params: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(JobEvaluations); diff --git a/frontend/src/components/JobInfo/JobInfo.js b/frontend/src/components/JobInfo/JobInfo.js index 7857eb62..6e90ed80 100644 --- a/frontend/src/components/JobInfo/JobInfo.js +++ b/frontend/src/components/JobInfo/JobInfo.js @@ -9,133 +9,133 @@ const jobProps = ['ID', 'Name', 'Region', 'Datacenters', 'Status', 'Priority']; class JobInfo extends Component { - render() { - const tasks = []; - const job = this.props.job; - const jobMetaBag = job.Meta || {}; + render() { + const tasks = []; + const job = this.props.job; + const jobMetaBag = job.Meta || {}; // Build the task groups table - const taskGroups = job.TaskGroups.map((taskGroup) => { - taskGroup.Tasks.map((task) => { - tasks.push( - - - - { taskGroup.Name } - - - - - { task.Name } - - - { task.Driver } - { task.Resources.CPU } - { task.Resources.MemoryMB } - { task.Resources.DiskMB } - - + const taskGroups = job.TaskGroups.map((taskGroup) => { + taskGroup.Tasks.map((task) => { + tasks.push( + + + + { taskGroup.Name } + + + + + { task.Name } + + + { task.Driver } + { task.Resources.CPU } + { task.Resources.MemoryMB } + { task.Resources.DiskMB } + + ); - return null; - }); - - const taskGroupMeta = taskGroup.Meta || {}; - return ( - - - - { taskGroup.Name } - - - { taskGroup.Count } - { taskGroup.Tasks.length } - - { taskGroup.RestartPolicy.Mode } - - - ); - }); - - return ( -
    -
    -
    - Job Properties -
    - { jobProps.map((jobProp) => { - let jobPropValue = this.props.job[jobProp]; - if (Array.isArray(jobPropValue)) { - jobPropValue = jobPropValue.join(', '); - } - - const result = []; - result.push(
    { jobProp }
    ); - result.push(
    { jobPropValue }
    ); - - return result; - }, this)} -
    -
    -
    - Meta Properties - -
    -
    - -
    -
    - Constraints - -
    -
    - -
    -
    - Task Groups - { (taskGroups.length > 0) ? - + return null; + }); + + const taskGroupMeta = taskGroup.Meta || {}; + return ( + + + + + + + + + ); + }); + + return ( +
    +
    +
    + Job Properties +
    + { jobProps.map((jobProp) => { + let jobPropValue = this.props.job[jobProp]; + if (Array.isArray(jobPropValue)) { + jobPropValue = jobPropValue.join(', '); + } + + const result = []; + result.push(
    { jobProp }
    ); + result.push(
    { jobPropValue }
    ); + + return result; + }, this)} +
    +
    +
    + Meta Properties + +
    +
    + +
    +
    + Constraints + +
    +
    + +
    +
    + Task Groups + { (taskGroups.length > 0) ? +
    + + { taskGroup.Name } + + { taskGroup.Count }{ taskGroup.Tasks.length }{ taskGroup.RestartPolicy.Mode }
    : null } - - - -
    -
    - Tasks - { (tasks.length > 0) ? -
    + + + +
    +
    + Tasks + { (tasks.length > 0) ? +
    : null } - - - ); - } + + + ); + } } JobInfo.defaultProps = { - job: { - constraints: [], - }, - allocations: {}, - evaluations: {}, + job: { + constraints: [], + }, + allocations: {}, + evaluations: {}, }; function mapStateToProps({ job, allocations, evaluations }) { - return { job, allocations, evaluations }; + return { job, allocations, evaluations }; } JobInfo.propTypes = { - job: PropTypes.object.isRequired, + job: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(JobInfo); diff --git a/frontend/src/components/JobRaw/JobRaw.js b/frontend/src/components/JobRaw/JobRaw.js index d3adb45e..f773ba34 100644 --- a/frontend/src/components/JobRaw/JobRaw.js +++ b/frontend/src/components/JobRaw/JobRaw.js @@ -9,11 +9,11 @@ const JobRaw = ({ job }) => ; function mapStateToProps({ job }) { - return { job }; + return { job }; } JobRaw.propTypes = { - job: PropTypes.object.isRequired, + job: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(JobRaw); diff --git a/frontend/src/components/JobTaskGroups/JobTaskGroups.js b/frontend/src/components/JobTaskGroups/JobTaskGroups.js index 43e42fb8..0ead7cde 100644 --- a/frontend/src/components/JobTaskGroups/JobTaskGroups.js +++ b/frontend/src/components/JobTaskGroups/JobTaskGroups.js @@ -6,68 +6,68 @@ import RawJson from '../RawJson/RawJson'; import MetaPayload from '../MetaPayload/MetaPayload'; const taskGroupHeaders = [ - 'ID', - 'Name', - 'Count', - 'Meta', - 'Restart Policy', + 'ID', + 'Name', + 'Count', + 'Meta', + 'Restart Policy', ]; const JobTaskGroups = ({ job, location }) => { - const taskGroups = []; + const taskGroups = []; - job.TaskGroups.forEach((taskGroup) => { - taskGroups.push( - - - - - - - + job.TaskGroups.forEach((taskGroup) => { + taskGroups.push( + + + + + + + ); - }); + }); - let taskGroupId = location.query.taskGroupId; + let taskGroupId = location.query.taskGroupId; // Auto-select first task group if only one is available. - if (!taskGroupId && job.TaskGroups.length === 1) { - taskGroupId = job.TaskGroups[0].ID; - } - return ( -
    -
    -
    - Task Groups - { (taskGroups.length > 0) ? -
    { taskGroup.Name }{ taskGroup.Count }{ taskGroup.RestartPolicy.Mode }
    { taskGroup.Name }{ taskGroup.Count }{ taskGroup.RestartPolicy.Mode }
    + if (!taskGroupId && job.TaskGroups.length === 1) { + taskGroupId = job.TaskGroups[0].ID; + } + return ( +
    +
    +
    + Task Groups + { (taskGroups.length > 0) ? +
    : null } - -
    - Task Group: { taskGroupId } - { job.TaskGroups +
    +
    + Task Group: { taskGroupId } + { job.TaskGroups .filter(taskGroup => taskGroup.ID === taskGroupId) .map(taskGroup => ) .pop() } -
    - ); + + ); }; function mapStateToProps({ job }) { - return { job }; + return { job }; } JobTaskGroups.propTypes = { - job: PropTypes.object.isRequired, - location: PropTypes.object.isRequired, + job: PropTypes.object.isRequired, + location: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(JobTaskGroups); diff --git a/frontend/src/components/JobTasks/JobTasks.js b/frontend/src/components/JobTasks/JobTasks.js index 6624a53b..f0e5fd5e 100644 --- a/frontend/src/components/JobTasks/JobTasks.js +++ b/frontend/src/components/JobTasks/JobTasks.js @@ -5,92 +5,92 @@ import Table from '../Table/Table'; import RawJson from '../RawJson/RawJson'; const taskHeaders = [ - 'ID', - 'Name', - 'Group', - 'Driver', - 'CPU', - 'Memory', - 'Disk', + 'ID', + 'Name', + 'Group', + 'Driver', + 'CPU', + 'Memory', + 'Disk', ]; const JobTasks = ({ job, location }) => { - const tasks = []; - job.TaskGroups.forEach((taskGroup) => { - taskGroup.Tasks.forEach((task) => { - tasks.push( - - - - - - - - - + const tasks = []; + job.TaskGroups.forEach((taskGroup) => { + taskGroup.Tasks.forEach((task) => { + tasks.push( + + + + + + + + + ); - }); }); + }); - let taskGroupId = location.query.taskGroupId; - let taskId = location.query.taskId; + let taskGroupId = location.query.taskGroupId; + let taskId = location.query.taskId; // Auto-select first task if only one is available. - if (!taskGroupId && !taskId && tasks.length === 1) { - job.TaskGroups.forEach((taskGroup) => { - taskGroup.Tasks.forEach((task) => { - taskGroupId = taskGroup.ID; - taskId = task.ID; - }); - }); - } - return ( -
    -
    -
    - Tasks - { (tasks.length > 0) ? -
    - - {task.Name} - - { taskGroup.Name } - - { task.Driver }{ task.Resources.CPU }{ task.Resources.MemoryMB }{ task.Resources.DiskMB }
    + + {task.Name} + + { taskGroup.Name } + + { task.Driver }{ task.Resources.CPU }{ task.Resources.MemoryMB }{ task.Resources.DiskMB }
    + if (!taskGroupId && !taskId && tasks.length === 1) { + job.TaskGroups.forEach((taskGroup) => { + taskGroup.Tasks.forEach((task) => { + taskGroupId = taskGroup.ID; + taskId = task.ID; + }); + }); + } + return ( +
    +
    +
    + Tasks + { (tasks.length > 0) ? +
    : null } - -
    - Task: { (taskGroupId && taskId) ? `${taskGroupId}/${taskId}` : null} - { job.TaskGroups +
    +
    + Task: { (taskGroupId && taskId) ? `${taskGroupId}/${taskId}` : null} + { job.TaskGroups .filter(taskGroup => taskGroup.ID === taskGroupId) .map(taskGroup => taskGroup.Tasks .filter(task => task.ID === taskId) .map(task => ) .pop()) .pop()} -
    - ); + + ); }; function mapStateToProps({ job }) { - return { job }; + return { job }; } JobTasks.propTypes = { - job: PropTypes.object.isRequired, - location: PropTypes.object.isRequired, + job: PropTypes.object.isRequired, + location: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(JobTasks); diff --git a/frontend/src/components/MetaPayload/MetaPayload.js b/frontend/src/components/MetaPayload/MetaPayload.js index fd0e84c8..f92a172d 100644 --- a/frontend/src/components/MetaPayload/MetaPayload.js +++ b/frontend/src/components/MetaPayload/MetaPayload.js @@ -4,59 +4,59 @@ import uuid from 'node-uuid'; class MetaPayload extends Component { - render() { - const metaBag = this.props.metaBag || {}; - const dtWithClass = this.props.dtWithClass; - const sortKeys = this.props.sortKeys; - const asTooltip = this.props.asTooltip; - - let keys = Object.keys(metaBag || {}); - if (keys.length === 0) { - return (
    - No data found -
    ); - } - - const identifier = uuid.v1(); - const meta = []; - let metaTag = null; - - if (sortKeys) { - keys = keys.sort(); - } - - keys.forEach((key) => { - meta.push(
    { key }
    ); - meta.push(
    { metaBag[key] }
    ); - }); - - if (meta.length > 0) { - metaTag =
    { meta }
    ; - } - - if (asTooltip) { - return ( -
    - { metaTag } - { keys.length } keys -
    - ); - } - - return metaTag; + render() { + const metaBag = this.props.metaBag || {}; + const dtWithClass = this.props.dtWithClass; + const sortKeys = this.props.sortKeys; + const asTooltip = this.props.asTooltip; + + let keys = Object.keys(metaBag || {}); + if (keys.length === 0) { + return (
    - No data found -
    ); } + + const identifier = uuid.v1(); + const meta = []; + let metaTag = null; + + if (sortKeys) { + keys = keys.sort(); + } + + keys.forEach((key) => { + meta.push(
    { key }
    ); + meta.push(
    { metaBag[key] }
    ); + }); + + if (meta.length > 0) { + metaTag =
    { meta }
    ; + } + + if (asTooltip) { + return ( +
    + { metaTag } + { keys.length } keys +
    + ); + } + + return metaTag; + } } MetaPayload.defaultProps = { - metaBag: {}, - dtWithClass: 'default', - sortKeys: true, - asTooltip: false, + metaBag: {}, + dtWithClass: 'default', + sortKeys: true, + asTooltip: false, }; MetaPayload.propTypes = { - metaBag: PropTypes.object, - dtWithClass: PropTypes.string.isRequired, - sortKeys: PropTypes.bool.isRequired, - asTooltip: PropTypes.bool.isRequired, + metaBag: PropTypes.object, + dtWithClass: PropTypes.string.isRequired, + sortKeys: PropTypes.bool.isRequired, + asTooltip: PropTypes.bool.isRequired, }; export default MetaPayload; diff --git a/frontend/src/components/NodeStatus/NodeStatus.js b/frontend/src/components/NodeStatus/NodeStatus.js index 173470b4..59fbb032 100644 --- a/frontend/src/components/NodeStatus/NodeStatus.js +++ b/frontend/src/components/NodeStatus/NodeStatus.js @@ -2,27 +2,27 @@ import React, { PropTypes } from 'react'; import FormatBoolean from '../FormatBoolean/FormatBoolean'; const NodeStatus = ({ value }) => { - switch (value) { - case 'initializing': - return (initializing); + switch (value) { + case 'initializing': + return (initializing); - case 'ready': - return (); + case 'ready': + return (); - case 'down': - return (); + case 'down': + return (); - default: - return ({value}); - } + default: + return ({value}); + } }; NodeStatus.defaultProps = { - value: null, + value: null, }; NodeStatus.propTypes = { - value: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, }; export default NodeStatus; diff --git a/frontend/src/components/NomadLink/NomadLink.js b/frontend/src/components/NomadLink/NomadLink.js index 610d9fd9..28b8538c 100644 --- a/frontend/src/components/NomadLink/NomadLink.js +++ b/frontend/src/components/NomadLink/NomadLink.js @@ -6,168 +6,168 @@ let nodeIdToNameCache = {}; export default class NomadLink extends Component { - componentWillReceiveProps(nextProps) { - if (nextProps.nodeList !== this.props.nodeList) { - nodeIdToNameCache = {}; - } + componentWillReceiveProps(nextProps) { + if (nextProps.nodeList !== this.props.nodeList) { + nodeIdToNameCache = {}; } + } - findNodeNameById(nodeId) { - if (nodeId in nodeIdToNameCache) { - return nodeIdToNameCache[nodeId]; - } + findNodeNameById(nodeId) { + if (nodeId in nodeIdToNameCache) { + return nodeIdToNameCache[nodeId]; + } - const r = Object.keys(this.props.nodeList) + const r = Object.keys(this.props.nodeList) .filter(node => this.props.nodeList[node].ID === nodeId ); - if (r.length !== 0) { - nodeIdToNameCache[nodeId] = this.props.nodeList[r].Name; - } else { - nodeIdToNameCache[nodeId] = false; - } - - return nodeIdToNameCache[nodeId]; + if (r.length !== 0) { + nodeIdToNameCache[nodeId] = this.props.nodeList[r].Name; + } else { + nodeIdToNameCache[nodeId] = false; } - render() { - const short = this.props.short === 'true'; - const linkAppend = this.props.linkAppend || ''; + return nodeIdToNameCache[nodeId]; + } + + render() { + const short = this.props.short === 'true'; + const linkAppend = this.props.linkAppend || ''; - let children = this.props.children; - const linkProps = Object.assign({}, this.props); - Object.keys(linkProps).filter(key => key.endsWith('Id')).forEach((key) => { - delete linkProps[key]; - }); - delete linkProps.short; - delete linkProps.nodeList; - delete linkProps.linkAppend; + let children = this.props.children; + const linkProps = Object.assign({}, this.props); + Object.keys(linkProps).filter(key => key.endsWith('Id')).forEach((key) => { + delete linkProps[key]; + }); + delete linkProps.short; + delete linkProps.nodeList; + delete linkProps.linkAppend; // member - if (this.props.memberId !== undefined) { - const memberId = this.props.memberId; - if (children === undefined) { - children = short ? shortUUID(memberId) : memberId; - } - return ( - { children } - ); - } + if (this.props.memberId !== undefined) { + const memberId = this.props.memberId; + if (children === undefined) { + children = short ? shortUUID(memberId) : memberId; + } + return ( + { children } + ); + } // node - if (this.props.nodeId !== undefined) { - const nodeId = this.props.nodeId; - if (children === undefined) { - if (this.props.nodeList) { - children = this.findNodeNameById(this.props.nodeId); - } - - if (!children) { - children = short ? shortUUID(nodeId) : nodeId; - } - } - - return ( - { children } - ); + if (this.props.nodeId !== undefined) { + const nodeId = this.props.nodeId; + if (children === undefined) { + if (this.props.nodeList) { + children = this.findNodeNameById(this.props.nodeId); } - // eval - if (this.props.evalId !== undefined) { - const evalId = this.props.evalId; - if (children === undefined) { - children = short ? shortUUID(evalId) : evalId; - } - return ( - { children } - ); + if (!children) { + children = short ? shortUUID(nodeId) : nodeId; } + } + + return ( + { children } + ); + } + + // eval + if (this.props.evalId !== undefined) { + const evalId = this.props.evalId; + if (children === undefined) { + children = short ? shortUUID(evalId) : evalId; + } + return ( + { children } + ); + } // alloc - if (this.props.allocId !== undefined) { - const allocId = this.props.allocId; - if (children === undefined) { - children = short ? shortUUID(allocId) : allocId; - } - - return ( - { children } - ); - } + if (this.props.allocId !== undefined) { + const allocId = this.props.allocId; + if (children === undefined) { + children = short ? shortUUID(allocId) : allocId; + } + + return ( + { children } + ); + } // tasks - if (this.props.taskId !== undefined) { - if (this.props.jobId !== undefined && this.props.taskGroupId !== undefined) { - const jobId = this.props.jobId; - const jobIdUrl = encodeURIComponent(jobId); - const taskGroupId = this.props.taskGroupId; - const taskId = this.props.taskId; - - if (children === undefined) { - children = short ? shortUUID(taskId) : taskId; - } - return ( - - { children } - - ); - } - console.error('NomadLink: You must also provide taskGroupId and jobId for task links!'); + if (this.props.taskId !== undefined) { + if (this.props.jobId !== undefined && this.props.taskGroupId !== undefined) { + const jobId = this.props.jobId; + const jobIdUrl = encodeURIComponent(jobId); + const taskGroupId = this.props.taskGroupId; + const taskId = this.props.taskId; + + if (children === undefined) { + children = short ? shortUUID(taskId) : taskId; } + return ( + + { children } + + ); + } + console.error('NomadLink: You must also provide taskGroupId and jobId for task links!'); + } // taskGroup (must be after task) - if (this.props.taskGroupId !== undefined) { - if (this.props.jobId !== undefined) { - const jobId = this.props.jobId; - const jobIdUrl = encodeURIComponent(jobId); - const taskGroupId = this.props.taskGroupId; - - if (children === undefined) { - children = short ? shortUUID(taskGroupId) : taskGroupId; - } - - return ( - - { children } - - ); - } - console.error('NomadLink: You must also provide jobId for taskGroup links!'); + if (this.props.taskGroupId !== undefined) { + if (this.props.jobId !== undefined) { + const jobId = this.props.jobId; + const jobIdUrl = encodeURIComponent(jobId); + const taskGroupId = this.props.taskGroupId; + + if (children === undefined) { + children = short ? shortUUID(taskGroupId) : taskGroupId; } + return ( + + { children } + + ); + } + console.error('NomadLink: You must also provide jobId for taskGroup links!'); + } + // job (must be after task & taskGroup - if (this.props.jobId !== undefined) { - const jobId = this.props.jobId; - const jobIdUrl = encodeURIComponent(jobId); - - if (children === undefined) { - children = short ? shortUUID(jobId) : jobId; - } - return ( - { children } - ); - } + if (this.props.jobId !== undefined) { + const jobId = this.props.jobId; + const jobIdUrl = encodeURIComponent(jobId); + + if (children === undefined) { + children = short ? shortUUID(jobId) : jobId; + } + return ( + { children } + ); + } // nothing by default - return null; - } + return null; + } } NomadLink.propTypes = { - nodeList: PropTypes.array, - short: PropTypes.string, - children: PropTypes.oneOfType([ - PropTypes.array, - PropTypes.string, - React.PropTypes.node, - ]), - memberId: PropTypes.string, - nodeId: PropTypes.string, - evalId: PropTypes.string, - allocId: PropTypes.string, - taskId: PropTypes.string, - jobId: PropTypes.string, - linkAppend: PropTypes.string, - taskGroupId: PropTypes.string, + nodeList: PropTypes.array, + short: PropTypes.string, + children: PropTypes.oneOfType([ + PropTypes.array, + PropTypes.string, + React.PropTypes.node, + ]), + memberId: PropTypes.string, + nodeId: PropTypes.string, + evalId: PropTypes.string, + allocId: PropTypes.string, + taskId: PropTypes.string, + jobId: PropTypes.string, + linkAppend: PropTypes.string, + taskGroupId: PropTypes.string, }; diff --git a/frontend/src/components/Progressbar/Progressbar.js b/frontend/src/components/Progressbar/Progressbar.js index 620dd971..6b117349 100644 --- a/frontend/src/components/Progressbar/Progressbar.js +++ b/frontend/src/components/Progressbar/Progressbar.js @@ -3,83 +3,83 @@ import { ProgressBar } from 'react-bootstrap'; class Progressbar extends Component { - colorIndex(index) { - return { + colorIndex(index) { + return { // client status - ready: 'success', - initializing: 'warning', - down: 'danger', + ready: 'success', + initializing: 'warning', + down: 'danger', // server status - alive: 'success', - leaving: 'warning', - left: 'danger', - shutdown: 'danger', + alive: 'success', + leaving: 'warning', + left: 'danger', + shutdown: 'danger', // job status - running: 'success', - pending: 'warning', - dead: 'info', + running: 'success', + pending: 'warning', + dead: 'info', // job type - service: 'success', - batch: 'info', - system: 'primary', + service: 'success', + batch: 'info', + system: 'primary', // task states // running: 'success', - starting: 'warning', - queued: 'info', - failed: 'danger', - lost: 'danger', - }[index]; - } + starting: 'warning', + queued: 'info', + failed: 'danger', + lost: 'danger', + }[index]; + } - render() { - const keys = Object.keys(this.props.data); - const normalizedValues = {}; - keys.forEach(key => (normalizedValues[key.toLowerCase()] = this.props.data[key])); - const normalizedKeys = keys.map(string => string.toLowerCase()); - const sum = normalizedKeys.reduce((previous, currentValue) => { - return previous + normalizedValues[currentValue]; - }, 0); + render() { + const keys = Object.keys(this.props.data); + const normalizedValues = {}; + keys.forEach(key => (normalizedValues[key.toLowerCase()] = this.props.data[key])); + const normalizedKeys = keys.map(string => string.toLowerCase()); + const sum = normalizedKeys.reduce((previous, currentValue) => { + return previous + normalizedValues[currentValue]; + }, 0); - return ( -
    -
    -
    { this.props.title }
    + return ( +
    +
    +
    { this.props.title }
    - - {normalizedKeys.map((index) => { - return ( - - ); - })} - + + {normalizedKeys.map((index) => { + return ( + + ); + })} + - {normalizedKeys.map((index) => { - return ( - - - { index } ({ normalizedValues[index] }) + {normalizedKeys.map((index) => { + return ( + + + { index } ({ normalizedValues[index] }) - ); - })} -
    -
    - ); - } + ); + })} +
    +
    + ); + } } Progressbar.propTypes = { - data: PropTypes.object.isRequired, - title: PropTypes.string.isRequired, + data: PropTypes.object.isRequired, + title: PropTypes.string.isRequired, }; export default Progressbar; diff --git a/frontend/src/components/RawJson/RawJson.js b/frontend/src/components/RawJson/RawJson.js index 49bf1580..7f962e8c 100644 --- a/frontend/src/components/RawJson/RawJson.js +++ b/frontend/src/components/RawJson/RawJson.js @@ -3,39 +3,39 @@ import JSONFormatter from 'json-formatter-js'; class Json extends Component { - componentDidMount() { - const formatter = new JSONFormatter(this.props.json, 2, { - hoverPreviewEnabled: true, - hoverPreviewArrayCount: 100, - hoverPreviewFieldCount: 5, - }); - this.json.appendChild(formatter.render()); - } + componentDidMount() { + const formatter = new JSONFormatter(this.props.json, 2, { + hoverPreviewEnabled: true, + hoverPreviewArrayCount: 100, + hoverPreviewFieldCount: 5, + }); + this.json.appendChild(formatter.render()); + } - componentDidUpdate() { - const formatter = new JSONFormatter(this.props.json, 2, { - hoverPreviewEnabled: true, - hoverPreviewArrayCount: 100, - hoverPreviewFieldCount: 5, - }); + componentDidUpdate() { + const formatter = new JSONFormatter(this.props.json, 2, { + hoverPreviewEnabled: true, + hoverPreviewArrayCount: 100, + hoverPreviewFieldCount: 5, + }); // Remove the old JSON - if (this.json.hasChildNodes()) { - this.json.removeChild(this.json.childNodes[0]); - } - // Add the new JSON - this.json.appendChild(formatter.render()); + if (this.json.hasChildNodes()) { + this.json.removeChild(this.json.childNodes[0]); } + // Add the new JSON + this.json.appendChild(formatter.render()); + } - render() { - return ( -
    { this.json = c; } }>
    - ); - } + render() { + return ( +
    { this.json = c; } }>
    + ); + } } Json.propTypes = { - json: PropTypes.object.isRequired, + json: PropTypes.object.isRequired, }; export default Json; diff --git a/frontend/src/components/ServerInfo/ServerInfo.js b/frontend/src/components/ServerInfo/ServerInfo.js index a628da6e..a8f4c6e5 100644 --- a/frontend/src/components/ServerInfo/ServerInfo.js +++ b/frontend/src/components/ServerInfo/ServerInfo.js @@ -3,57 +3,57 @@ import { connect } from 'react-redux'; import Table from '../Table/Table'; const memberProps = [ - 'ID', - 'Name', - 'Address', - 'Port', - 'Status', + 'ID', + 'Name', + 'Address', + 'Port', + 'Status', ]; const ServerInfo = ({ member }) => { - const tags = member.Tags; + const tags = member.Tags; - const memberTags = Object.keys(tags).map((key) => { - const name = key; - const value = tags[key]; - - return ( -
    - - - - ); - }); + const memberTags = Object.keys(tags).map((key) => { + const name = key; + const value = tags[key]; return ( -
    -
    - Server Properties -
    - { memberProps.map(memberProp => -
    -
    { memberProp }
    -
    { member[memberProp] }
    -
    +
    + + + + ); + }); + + return ( +
    +
    + Server Properties +
    + { memberProps.map(memberProp => +
    +
    { memberProp }
    +
    { member[memberProp] }
    +
    )} -
    -
    - Server Tags - { (memberTags.length > 0) ? -
    { name }{ value }
    { name }{ value }
    + +
    + Server Tags + { (memberTags.length > 0) ? +
    : null } - - ); + + ); }; function mapStateToProps({ member }) { - return { member }; + return { member }; } ServerInfo.propTypes = { - member: PropTypes.object.isRequired, + member: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(ServerInfo); diff --git a/frontend/src/components/ServerRaw/ServerRaw.js b/frontend/src/components/ServerRaw/ServerRaw.js index e7ce8363..cef041b6 100644 --- a/frontend/src/components/ServerRaw/ServerRaw.js +++ b/frontend/src/components/ServerRaw/ServerRaw.js @@ -9,11 +9,11 @@ const ServerRaw = ({ member }) => ; function mapStateToProps({ member }) { - return { member }; + return { member }; } ServerRaw.propTypes = { - member: PropTypes.object.isRequired, + member: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(ServerRaw); diff --git a/frontend/src/components/Sidebar/Sidebar.js b/frontend/src/components/Sidebar/Sidebar.js index d0703eb3..138a25db 100644 --- a/frontend/src/components/Sidebar/Sidebar.js +++ b/frontend/src/components/Sidebar/Sidebar.js @@ -4,77 +4,77 @@ import { Link } from 'react-router'; class Sidebar extends PureComponent { /* eslint class-methods-use-this: 0*/ - onClickMenu() { - window.document.querySelector('html').classList.toggle('sidebar-mini'); - } + onClickMenu() { + window.document.querySelector('html').classList.toggle('sidebar-mini'); + } - onLinkClick() { - window.document.querySelector('html').classList.remove('nav-open'); - } + onLinkClick() { + window.document.querySelector('html').classList.remove('nav-open'); + } - render() { - return ( -
    -
    - + render() { + return ( +
    +
    + Nomad - -
    -
    - N - -
    -
    -
      -
    • - - -

      Cluster

      - -
    • -
    • - - -

      Jobs

      - -
    • -
    • - - -

      Allocations

      - -
    • -
    • - - -

      Evaluations

      - -
    • -
    • - - -

      Clients

      - -
    • -
    • - - -

      Servers

      - -
    • -
    -
    -
    -
    - ); - } +
    +
    +
    + N + +
    +
    +
      +
    • + + +

      Cluster

      + +
    • +
    • + + +

      Jobs

      + +
    • +
    • + + +

      Allocations

      + +
    • +
    • + + +

      Evaluations

      + +
    • +
    • + + +

      Clients

      + +
    • +
    • + + +

      Servers

      + +
    • +
    +
    +
    +
    + ); + } } Sidebar.propTypes = { - location: PropTypes.object.isRequired, + location: PropTypes.object.isRequired, }; export default Sidebar; diff --git a/frontend/src/components/Table/Table.js b/frontend/src/components/Table/Table.js index 8a208cf5..e4d5eea4 100644 --- a/frontend/src/components/Table/Table.js +++ b/frontend/src/components/Table/Table.js @@ -15,9 +15,9 @@ const Table = ({ classes, headers, body }) => ; Table.propTypes = { - classes: PropTypes.string.isRequired, - headers: PropTypes.array.isRequired, - body: PropTypes.array.isRequired, + classes: PropTypes.string.isRequired, + headers: PropTypes.array.isRequired, + body: PropTypes.array.isRequired, }; export default Table; diff --git a/frontend/src/components/Tabs/Tabs.js b/frontend/src/components/Tabs/Tabs.js index f1469162..6a790ef8 100644 --- a/frontend/src/components/Tabs/Tabs.js +++ b/frontend/src/components/Tabs/Tabs.js @@ -22,10 +22,10 @@ const Tabs = ({ children, tabs, tabSlug, basePath }) => ; Tabs.propTypes = { - tabs: PropTypes.array.isRequired, - tabSlug: PropTypes.string.isRequired, - basePath: PropTypes.string.isRequired, - children: PropTypes.object.isRequired, + tabs: PropTypes.array.isRequired, + tabSlug: PropTypes.string.isRequired, + basePath: PropTypes.string.isRequired, + children: PropTypes.object.isRequired, }; export default Tabs; diff --git a/frontend/src/components/Topbar/Topbar.js b/frontend/src/components/Topbar/Topbar.js index 6e2ca2ff..5fedb246 100644 --- a/frontend/src/components/Topbar/Topbar.js +++ b/frontend/src/components/Topbar/Topbar.js @@ -3,33 +3,33 @@ import React, { PureComponent } from 'react'; class Topbar extends PureComponent { /* eslint class-methods-use-this: 0*/ - onClick() { - window.document.querySelector('html').classList.toggle('nav-open'); - } + onClick() { + window.document.querySelector('html').classList.toggle('nav-open'); + } - render() { - return ( - - ); - } + render() { + return ( + + ); + } } // Topbar.propTypes = { diff --git a/frontend/src/components/app.js b/frontend/src/components/app.js index 605d9711..abf86704 100644 --- a/frontend/src/components/app.js +++ b/frontend/src/components/app.js @@ -4,26 +4,26 @@ import Topbar from './Topbar/Topbar'; class App extends PureComponent { - render() { - return ( -
    - -
    - -
    -
    - { this.props.children } -
    -
    + render() { + return ( +
    + +
    + +
    +
    + { this.props.children }
    - ); - } +
    +
    + ); + } } App.propTypes = { - location: PropTypes.object.isRequired, - children: PropTypes.object.isRequired, + location: PropTypes.object.isRequired, + children: PropTypes.object.isRequired, }; export default App; diff --git a/frontend/src/containers/allocation.js b/frontend/src/containers/allocation.js index 1d31f3da..36a4bf05 100644 --- a/frontend/src/containers/allocation.js +++ b/frontend/src/containers/allocation.js @@ -5,81 +5,81 @@ import { WATCH_ALLOC, UNWATCH_ALLOC } from '../sagas/event'; class Allocation extends Component { - constructor(props) { - super(props); + constructor(props) { + super(props); - this.state = { - tabs: [ - { - name: 'Info', - path: 'info', - }, - { - name: 'Files', - path: 'files', - }, - { - name: 'Logs', - path: 'logs', - }, - { - name: 'Raw', - path: 'raw', - }, - ], - }; - } + this.state = { + tabs: [ + { + name: 'Info', + path: 'info', + }, + { + name: 'Files', + path: 'files', + }, + { + name: 'Logs', + path: 'logs', + }, + { + name: 'Raw', + path: 'raw', + }, + ], + }; + } - componentWillMount() { - this.props.dispatch({ - type: WATCH_ALLOC, - payload: this.props.params.allocId, - }); - } + componentWillMount() { + this.props.dispatch({ + type: WATCH_ALLOC, + payload: this.props.params.allocId, + }); + } - componentWillUnmount() { - this.props.dispatch({ - type: UNWATCH_ALLOC, - payload: this.props.params.allocId, - }); - } + componentWillUnmount() { + this.props.dispatch({ + type: UNWATCH_ALLOC, + payload: this.props.params.allocId, + }); + } - render() { - if (this.props.allocation == null) return (null); + render() { + if (this.props.allocation == null) return (null); - const path = this.props.location.pathname; - const tabSlug = path.split('/').pop(); - const basePath = path.substring(0, path.lastIndexOf('/')); + const path = this.props.location.pathname; + const tabSlug = path.split('/').pop(); + const basePath = path.substring(0, path.lastIndexOf('/')); - return ( -
    -
    -
    -
    -

    Allocation: { this.props.allocation.Name }

    -
    -
    - - { this.props.children } - -
    -
    + return ( +
    +
    +
    +
    +

    Allocation: { this.props.allocation.Name }

    +
    +
    + + { this.props.children } +
    - ); - } +
    +
    + ); + } } function mapStateToProps({ allocation }) { - return { allocation }; + return { allocation }; } Allocation.propTypes = { - dispatch: PropTypes.func.isRequired, - params: PropTypes.object.isRequired, - allocation: PropTypes.object.isRequired, - location: PropTypes.object.isRequired, - children: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired, + params: PropTypes.object.isRequired, + allocation: PropTypes.object.isRequired, + location: PropTypes.object.isRequired, + children: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(Allocation); diff --git a/frontend/src/containers/allocations.js b/frontend/src/containers/allocations.js index 5fee7dbb..5d772748 100644 --- a/frontend/src/containers/allocations.js +++ b/frontend/src/containers/allocations.js @@ -4,34 +4,34 @@ import AllocationList from '../components/AllocationList/AllocationList'; class Allocations extends Component { - render() { - return ( -
    -
    -
    -
    -

    Allocations

    -
    - -
    + render() { + return ( +
    +
    +
    +
    +

    Allocations

    +
    - ); - } +
    +
    + ); + } } function mapStateToProps({ allocations, nodes }) { - return { allocations, nodes }; + return { allocations, nodes }; } Allocations.propTypes = { - allocations: PropTypes.array.isRequired, - nodes: PropTypes.array.isRequired, + allocations: PropTypes.array.isRequired, + nodes: PropTypes.array.isRequired, }; export default connect(mapStateToProps)(Allocations); diff --git a/frontend/src/containers/client.js b/frontend/src/containers/client.js index 5e2d733e..a6531753 100644 --- a/frontend/src/containers/client.js +++ b/frontend/src/containers/client.js @@ -5,81 +5,81 @@ import { WATCH_NODE, UNWATCH_NODE } from '../sagas/event'; class Client extends Component { - constructor(props) { - super(props); + constructor(props) { + super(props); - this.state = { - tabs: [ - { - name: 'Info', - path: 'info', - }, - { - name: 'Allocations', - path: 'allocations', - }, - { - name: 'Evaluations', - path: 'evaluations', - }, - { - name: 'Raw', - path: 'raw', - }, - ], - }; - } + this.state = { + tabs: [ + { + name: 'Info', + path: 'info', + }, + { + name: 'Allocations', + path: 'allocations', + }, + { + name: 'Evaluations', + path: 'evaluations', + }, + { + name: 'Raw', + path: 'raw', + }, + ], + }; + } - componentWillMount() { - this.props.dispatch({ - type: WATCH_NODE, - payload: this.props.params.nodeId, - }); - } + componentWillMount() { + this.props.dispatch({ + type: WATCH_NODE, + payload: this.props.params.nodeId, + }); + } - componentWillUnmount() { - this.props.dispatch({ - type: UNWATCH_NODE, - payload: this.props.params.nodeId, - }); - } + componentWillUnmount() { + this.props.dispatch({ + type: UNWATCH_NODE, + payload: this.props.params.nodeId, + }); + } - render() { - if (this.props.node == null) return (null); + render() { + if (this.props.node == null) return (null); - const path = this.props.location.pathname; - const tabSlug = path.split('/').pop(); - const basePath = path.substring(0, path.lastIndexOf('/')); + const path = this.props.location.pathname; + const tabSlug = path.split('/').pop(); + const basePath = path.substring(0, path.lastIndexOf('/')); - return ( -
    -
    -
    -
    -

    Client: { this.props.node.Name }

    -
    -
    - - { this.props.children } - -
    -
    + return ( +
    +
    +
    +
    +

    Client: { this.props.node.Name }

    +
    +
    + + { this.props.children } +
    - ); - } +
    +
    + ); + } } function mapStateToProps({ node }) { - return { node }; + return { node }; } Client.propTypes = { - dispatch: PropTypes.func.isRequired, - params: PropTypes.object.isRequired, - node: PropTypes.object.isRequired, - location: PropTypes.object.isRequired, - children: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired, + params: PropTypes.object.isRequired, + node: PropTypes.object.isRequired, + location: PropTypes.object.isRequired, + children: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(Client); diff --git a/frontend/src/containers/clients.js b/frontend/src/containers/clients.js index b1c39ccb..eb55be94 100644 --- a/frontend/src/containers/clients.js +++ b/frontend/src/containers/clients.js @@ -42,11 +42,11 @@ const Clients = ({ nodes }) =>
    ; function mapStateToProps({ nodes }) { - return { nodes }; + return { nodes }; } Clients.propTypes = { - nodes: PropTypes.array.isRequired, + nodes: PropTypes.array.isRequired, }; export default connect(mapStateToProps)(Clients); diff --git a/frontend/src/containers/cluster.js b/frontend/src/containers/cluster.js index d79f700c..1862d0bd 100644 --- a/frontend/src/containers/cluster.js +++ b/frontend/src/containers/cluster.js @@ -6,81 +6,81 @@ import Statistics from './statistics'; class Cluster extends Component { - getChartData() { - const stats = { - jobStatus: { - running: 0, - pending: 0, - dead: 0, - }, - jobTypes: { - service: 0, - batch: 0, - system: 0, - }, - nodeStatus: { - ready: 0, - initializing: 0, - down: 0, - }, - memberStatus: { - alive: 0, - leaving: 0, - left: 0, - shutdown: 0, - }, - }; + getChartData() { + const stats = { + jobStatus: { + running: 0, + pending: 0, + dead: 0, + }, + jobTypes: { + service: 0, + batch: 0, + system: 0, + }, + nodeStatus: { + ready: 0, + initializing: 0, + down: 0, + }, + memberStatus: { + alive: 0, + leaving: 0, + left: 0, + shutdown: 0, + }, + }; - for (const job of this.props.jobs) { - stats.jobStatus[job.Status] += 1; - stats.jobTypes[job.Type] += 1; - } - - for (const node of this.props.nodes) { - stats.nodeStatus[node.Status] += 1; - } + for (const job of this.props.jobs) { + stats.jobStatus[job.Status] += 1; + stats.jobTypes[job.Type] += 1; + } - for (const member of this.props.members) { - stats.memberStatus[member.Status] += 1; - } + for (const node of this.props.nodes) { + stats.nodeStatus[node.Status] += 1; + } - return stats; + for (const member of this.props.members) { + stats.memberStatus[member.Status] += 1; } - render() { - const data = this.getChartData(); + return stats; + } + + render() { + const data = this.getChartData(); - return ( -
    -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - - + return ( +
    +
    +
    +
    - ); - } +
    + +
    +
    + +
    +
    + +
    +
    + + +
    + ); + } } function mapStateToProps({ jobs, nodes, members }) { - return { jobs, nodes, members }; + return { jobs, nodes, members }; } Cluster.propTypes = { - jobs: PropTypes.array.isRequired, - nodes: PropTypes.array.isRequired, - members: PropTypes.array.isRequired, + jobs: PropTypes.array.isRequired, + nodes: PropTypes.array.isRequired, + members: PropTypes.array.isRequired, }; export default connect(mapStateToProps)(Cluster); diff --git a/frontend/src/containers/evaluation.js b/frontend/src/containers/evaluation.js index e8b9604a..9fdede6e 100644 --- a/frontend/src/containers/evaluation.js +++ b/frontend/src/containers/evaluation.js @@ -5,77 +5,77 @@ import { WATCH_EVAL, UNWATCH_EVAL } from '../sagas/event'; class Evaluation extends Component { - constructor(props) { - super(props); + constructor(props) { + super(props); - this.state = { - tabs: [ - { - name: 'Info', - path: 'info', - }, - { - name: 'Allocations', - path: 'allocations', - }, - { - name: 'Raw', - path: 'raw', - }, - ], - }; - } + this.state = { + tabs: [ + { + name: 'Info', + path: 'info', + }, + { + name: 'Allocations', + path: 'allocations', + }, + { + name: 'Raw', + path: 'raw', + }, + ], + }; + } - componentWillMount() { - this.props.dispatch({ - type: WATCH_EVAL, - payload: this.props.params.evalId, - }); - } + componentWillMount() { + this.props.dispatch({ + type: WATCH_EVAL, + payload: this.props.params.evalId, + }); + } - componentWillUnmount() { - this.props.dispatch({ - type: UNWATCH_EVAL, - payload: this.props.params.evalId, - }); - } + componentWillUnmount() { + this.props.dispatch({ + type: UNWATCH_EVAL, + payload: this.props.params.evalId, + }); + } - render() { - if (this.props.evaluation == null) return (null); + render() { + if (this.props.evaluation == null) return (null); - const path = this.props.location.pathname; - const tabSlug = path.split('/').pop(); - const basePath = path.substring(0, path.lastIndexOf('/')); + const path = this.props.location.pathname; + const tabSlug = path.split('/').pop(); + const basePath = path.substring(0, path.lastIndexOf('/')); - return ( -
    -
    -
    -
    -

    Evaluation: { this.props.evaluation.ID }

    -
    -
    - - { this.props.children } - -
    -
    + return ( +
    +
    +
    +
    +

    Evaluation: { this.props.evaluation.ID }

    +
    +
    + + { this.props.children } +
    - ); - } +
    +
    + ); + } } function mapStateToProps({ evaluation }) { - return { evaluation }; + return { evaluation }; } Evaluation.propTypes = { - dispatch: PropTypes.func.isRequired, - params: PropTypes.object.isRequired, - evaluation: PropTypes.object.isRequired, - location: PropTypes.object.isRequired, - children: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired, + params: PropTypes.object.isRequired, + evaluation: PropTypes.object.isRequired, + location: PropTypes.object.isRequired, + children: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(Evaluation); diff --git a/frontend/src/containers/evaluations.js b/frontend/src/containers/evaluations.js index aaa9d7c3..08511d31 100644 --- a/frontend/src/containers/evaluations.js +++ b/frontend/src/containers/evaluations.js @@ -15,15 +15,15 @@ const Evaluations = ({ evaluations }) =>
    ; function mapStateToProps({ evaluations }) { - return { evaluations }; + return { evaluations }; } Evaluations.defaultProps = { - evaluations: {}, + evaluations: {}, }; Evaluations.propTypes = { - evaluations: PropTypes.array.isRequired, + evaluations: PropTypes.array.isRequired, }; export default connect(mapStateToProps)(Evaluations); diff --git a/frontend/src/containers/events.js b/frontend/src/containers/events.js index 9a1edbdf..2754a82e 100644 --- a/frontend/src/containers/events.js +++ b/frontend/src/containers/events.js @@ -5,23 +5,23 @@ import FormatTime from '../components/FormatTime/FormatTime'; class Events extends Component { - render() { - const taskEvents = []; - this.props.allocations.forEach((allocation) => { - if (allocation.TaskStates != null) { - Object.keys(allocation.TaskStates).forEach((task) => { - allocation.TaskStates[task].Events.reverse().forEach((event) => { - if (taskEvents.length === 10) return; - const eventID = `${task}.${event.Time}`; - taskEvents.push( -
    - - - + + + - - + + + ); - }); - }); - } + }); }); + } + }); - return ( -
    -
    -
    -
    -

    Task Events

    -
    -
    -
    - - { allocation.JobID }.{ task } - - { event.Type }{ + render() { + const taskEvents = []; + this.props.allocations.forEach((allocation) => { + if (allocation.TaskStates != null) { + Object.keys(allocation.TaskStates).forEach((task) => { + allocation.TaskStates[task].Events.reverse().forEach((event) => { + if (taskEvents.length === 10) return; + const eventID = `${task}.${event.Time}`; + taskEvents.push( +
    + + { allocation.JobID }.{ task } + + { event.Type }{ event.KillError || event.DriverError || event.DownloadError || @@ -29,50 +29,50 @@ class Events extends Component { event.Message || '' } -
    - - - - - - - - - - { taskEvents } - -
    TaskTypeMessageTime
    -
    -
    + return ( +
    +
    +
    +
    +

    Task Events

    +
    +
    + + + + + + + + + + + { taskEvents } + +
    TaskTypeMessageTime
    - ); - } +
    +
    + ); + } } function mapStateToProps({ allocations }) { - return { allocations }; + return { allocations }; } Events.propTypes = { - allocations: PropTypes.array.isRequired, + allocations: PropTypes.array.isRequired, }; export default connect(mapStateToProps)(Events); diff --git a/frontend/src/containers/job.js b/frontend/src/containers/job.js index 0349ea5f..1b080ddd 100644 --- a/frontend/src/containers/job.js +++ b/frontend/src/containers/job.js @@ -5,89 +5,89 @@ import { WATCH_JOB, UNWATCH_JOB } from '../sagas/event'; class Job extends Component { - constructor(props) { - super(props); + constructor(props) { + super(props); - this.state = { - tabs: [ - { - name: 'Info', - path: 'info', - }, - { - name: 'Allocations', - path: 'allocations', - }, - { - name: 'Evaluations', - path: 'evaluations', - }, - { - name: 'Tasks Groups', - path: 'taskGroups', - }, - { - name: 'Tasks', - path: 'tasks', - }, - { - name: 'Raw', - path: 'raw', - }, - ], - }; - } + this.state = { + tabs: [ + { + name: 'Info', + path: 'info', + }, + { + name: 'Allocations', + path: 'allocations', + }, + { + name: 'Evaluations', + path: 'evaluations', + }, + { + name: 'Tasks Groups', + path: 'taskGroups', + }, + { + name: 'Tasks', + path: 'tasks', + }, + { + name: 'Raw', + path: 'raw', + }, + ], + }; + } - componentWillMount() { - this.props.dispatch({ - type: WATCH_JOB, - payload: this.props.params.jobId, - }); - } + componentWillMount() { + this.props.dispatch({ + type: WATCH_JOB, + payload: this.props.params.jobId, + }); + } - componentWillUnmount() { - this.props.dispatch({ - type: UNWATCH_JOB, - payload: this.props.params.jobId, - }); - } + componentWillUnmount() { + this.props.dispatch({ + type: UNWATCH_JOB, + payload: this.props.params.jobId, + }); + } - render() { - if (this.props.job == null) return (null); + render() { + if (this.props.job == null) return (null); - const path = this.props.location.pathname; - const tabSlug = path.split('/').pop(); - const basePath = path.substring(0, path.lastIndexOf('/')); + const path = this.props.location.pathname; + const tabSlug = path.split('/').pop(); + const basePath = path.substring(0, path.lastIndexOf('/')); - return ( -
    -
    -
    -
    -

    Job: { this.props.job.ID }

    -
    -
    - - { this.props.children } - -
    -
    + return ( +
    +
    +
    +
    +

    Job: { this.props.job.ID }

    +
    +
    + + { this.props.children } +
    - ); - } +
    +
    + ); + } } function mapStateToProps({ job }) { - return { job }; + return { job }; } Job.propTypes = { - dispatch: PropTypes.func.isRequired, - params: PropTypes.object.isRequired, - job: PropTypes.object.isRequired, - location: PropTypes.object.isRequired, - children: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired, + params: PropTypes.object.isRequired, + job: PropTypes.object.isRequired, + location: PropTypes.object.isRequired, + children: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(Job); diff --git a/frontend/src/containers/jobs.js b/frontend/src/containers/jobs.js index 885f8a83..82c04288 100644 --- a/frontend/src/containers/jobs.js +++ b/frontend/src/containers/jobs.js @@ -5,177 +5,177 @@ import { DropdownButton } from 'react-bootstrap'; import NomadLink from '../components/NomadLink/NomadLink'; const jobStatusColors = { - running: '', - pending: 'warning', - dead: 'danger', + running: '', + pending: 'warning', + dead: 'danger', }; const summaryLabels = ['Starting', 'Running', 'Queued', 'Complete', 'Failed', 'Lost']; const getJobStatisticsHeader = () => { - const output = []; + const output = []; - summaryLabels.forEach((key) => { - output.push({ key }); - }); + summaryLabels.forEach((key) => { + output.push({ key }); + }); - return output; -} + return output; +}; const getJobStatisticsRow = (job) => { - const counter = { - Queued: 0, - Complete: 0, - Failed: 0, - Running: 0, - Starting: 0, - Lost: 0, - }; - - if (job.JobSummary !== null) { - const summary = job.JobSummary.Summary; - Object.keys(summary).forEach((taskGroupID) => { - counter.Queued += summary[taskGroupID].Queued; - counter.Complete += summary[taskGroupID].Complete; - counter.Failed += summary[taskGroupID].Failed; - counter.Running += summary[taskGroupID].Running; - counter.Starting += summary[taskGroupID].Starting; - counter.Lost += summary[taskGroupID].Lost; - }); - } else { - Object.keys(counter).forEach(key => (counter[key] = 'N/A')); - } - - const output = []; - summaryLabels.forEach((key) => { - output.push({counter[key]}); + const counter = { + Queued: 0, + Complete: 0, + Failed: 0, + Running: 0, + Starting: 0, + Lost: 0, + }; + + if (job.JobSummary !== null) { + const summary = job.JobSummary.Summary; + Object.keys(summary).forEach((taskGroupID) => { + counter.Queued += summary[taskGroupID].Queued; + counter.Complete += summary[taskGroupID].Complete; + counter.Failed += summary[taskGroupID].Failed; + counter.Running += summary[taskGroupID].Running; + counter.Starting += summary[taskGroupID].Starting; + counter.Lost += summary[taskGroupID].Lost; }); + } else { + Object.keys(counter).forEach(key => (counter[key] = 'N/A')); + } - return output; -} + const output = []; + summaryLabels.forEach((key) => { + output.push({counter[key]}); + }); -class Jobs extends Component { + return output; +}; - filteredJobs() { - const query = this.props.location.query || {}; - let jobs = this.props.jobs; +class Jobs extends Component { - if ('job_type' in query) { - jobs = jobs.filter(job => job.Type === query.job_type); - } + filteredJobs() { + const query = this.props.location.query || {}; + let jobs = this.props.jobs; - if ('job_status' in query) { - jobs = jobs.filter(job => job.Status === query.job_status); - } + if ('job_type' in query) { + jobs = jobs.filter(job => job.Type === query.job_type); + } - return jobs; + if ('job_status' in query) { + jobs = jobs.filter(job => job.Status === query.job_status); } - jobTypeFilter() { - const location = this.props.location; - const query = this.props.location.query || {}; - - let title = 'Job Type'; - if ('job_type' in query) { - title = {title}: { query.job_type }; - } - - return ( - -
  • - Any -
  • -
  • System
  • -
  • Batch
  • -
  • Service
  • -
    - ); + return jobs; + } + + jobTypeFilter() { + const location = this.props.location; + const query = this.props.location.query || {}; + + let title = 'Job Type'; + if ('job_type' in query) { + title = {title}: { query.job_type }; } - jobStatusFilter() { - const location = this.props.location; - const query = this.props.location.query || {}; - - let title = 'Job Status'; - if ('job_status' in query) { - title = {title}: { query.job_status }; - } - - return ( - -
  • - Any -
  • -
  • Running
  • -
  • Pending
  • -
  • Dead
  • -
    - ); + return ( + +
  • - Any -
  • +
  • System
  • +
  • Batch
  • +
  • Service
  • +
    + ); + } + + jobStatusFilter() { + const location = this.props.location; + const query = this.props.location.query || {}; + + let title = 'Job Status'; + if ('job_status' in query) { + title = {title}: { query.job_status }; } - taskGroupCount(job) { - let taskGroupCount = 'N/A'; + return ( + +
  • - Any -
  • +
  • Running
  • +
  • Pending
  • +
  • Dead
  • +
    + ); + } - if (job.JobSummary !== null) { - taskGroupCount = Object.keys(job.JobSummary.Summary).length; - } + taskGroupCount(job) { + let taskGroupCount = 'N/A'; - return taskGroupCount; + if (job.JobSummary !== null) { + taskGroupCount = Object.keys(job.JobSummary.Summary).length; } - render() { - return ( -
    -
    -
    -
    -

    Jobs

    - {this.jobStatusFilter()} + return taskGroupCount; + } + + render() { + return ( +
    +
    +
    +
    +

    Jobs

    + {this.jobStatusFilter()}   - {this.jobTypeFilter()} -
    - -
    - - - - - - - - - { getJobStatisticsHeader() } - - - - { this.filteredJobs().map(job => - - - - - - - { getJobStatisticsRow(job) } - + {this.jobTypeFilter()} + + +
    +
    IDStatusTypePriorityTask Groups
    { job.Status }{ job.Type }{ job.Priority }{ this.taskGroupCount(job) }
    + + + + + + + + { getJobStatisticsHeader() } + + + + { this.filteredJobs().map(job => + + + + + + + { getJobStatisticsRow(job) } + )} - -
    IDStatusTypePriorityTask Groups
    { job.Status }{ job.Type }{ job.Priority }{ this.taskGroupCount(job) }
    -
    -
    + +
    - ); - } +
    +
    + ); + } } function mapStateToProps({ jobs }) { - return { jobs }; + return { jobs }; } Jobs.defaultProps = { - jobs: [], - location: {}, + jobs: [], + location: {}, }; Jobs.propTypes = { - jobs: PropTypes.array.isRequired, - location: PropTypes.object.isRequired, + jobs: PropTypes.array.isRequired, + location: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(Jobs); diff --git a/frontend/src/containers/server.js b/frontend/src/containers/server.js index 4bbaae33..098d4258 100644 --- a/frontend/src/containers/server.js +++ b/frontend/src/containers/server.js @@ -5,73 +5,73 @@ import { WATCH_MEMBER, UNWATCH_MEMBER } from '../sagas/event'; class Server extends Component { - constructor(props) { - super(props); + constructor(props) { + super(props); - this.state = { - tabs: [ - { - name: 'Info', - path: 'info', - }, - { - name: 'Raw', - path: 'raw', - }, - ], - }; - } + this.state = { + tabs: [ + { + name: 'Info', + path: 'info', + }, + { + name: 'Raw', + path: 'raw', + }, + ], + }; + } - componentWillMount() { - this.props.dispatch({ - type: WATCH_MEMBER, - payload: this.props.params.memberId, - }); - } + componentWillMount() { + this.props.dispatch({ + type: WATCH_MEMBER, + payload: this.props.params.memberId, + }); + } - componentWillUnmount() { - this.props.dispatch({ - type: UNWATCH_MEMBER, - payload: this.props.params.memberId, - }); - } + componentWillUnmount() { + this.props.dispatch({ + type: UNWATCH_MEMBER, + payload: this.props.params.memberId, + }); + } - render() { - if (this.props.member == null) return (null); + render() { + if (this.props.member == null) return (null); - const path = this.props.location.pathname; - const tabSlug = path.split('/').pop(); - const basePath = path.substring(0, path.lastIndexOf('/')); + const path = this.props.location.pathname; + const tabSlug = path.split('/').pop(); + const basePath = path.substring(0, path.lastIndexOf('/')); - return ( -
    -
    -
    -
    -

    Server: { this.props.member.Name }

    -
    -
    - - { this.props.children } - -
    -
    + return ( +
    +
    +
    +
    +

    Server: { this.props.member.Name }

    +
    +
    + + { this.props.children } +
    - ); - } +
    +
    + ); + } } function mapStateToProps({ member }) { - return { member }; + return { member }; } Server.propTypes = { - dispatch: PropTypes.func.isRequired, - params: PropTypes.object.isRequired, - location: PropTypes.object.isRequired, - member: PropTypes.object.isRequired, - children: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired, + params: PropTypes.object.isRequired, + location: PropTypes.object.isRequired, + member: PropTypes.object.isRequired, + children: PropTypes.object.isRequired, }; export default connect(mapStateToProps)(Server); diff --git a/frontend/src/containers/servers.js b/frontend/src/containers/servers.js index a798c342..d8e86539 100644 --- a/frontend/src/containers/servers.js +++ b/frontend/src/containers/servers.js @@ -4,62 +4,62 @@ import NomadLink from '../components/NomadLink/NomadLink'; import FormatBoolean from '../components/FormatBoolean/FormatBoolean'; const Servers = ({ members }) => { - return ( -
    -
    -
    -
    -

    Servers

    -
    -
    - - - - - - - - - - - - - - - - - { members.map((member) => { - return ( - - - - - - - - - - - - - ); - }) + return ( +
    +
    +
    +
    +

    Servers

    +
    +
    +
    IDNameAddressPortStatusLeaderProtocolBuildDatacenterRegion
    { member.Name }{ member.Addr }{ member.Port }{ member.Status }{ member.ProtocolCur }{ member.Tags.build }{ member.Tags.dc }{ member.Tags.region }
    + + + + + + + + + + + + + + + + { members.map((member) => { + return ( + + + + + + + + + + + + + ); + }) } - -
    IDNameAddressPortStatusLeaderProtocolBuildDatacenterRegion
    { member.Name }{ member.Addr }{ member.Port }{ member.Status }{ member.ProtocolCur }{ member.Tags.build }{ member.Tags.dc }{ member.Tags.region }
    -
    + +
    - ); +
    + ); }; function mapStateToProps({ members }) { - return { members }; + return { members }; } Servers.propTypes = { - members: PropTypes.array.isRequired, + members: PropTypes.array.isRequired, }; export default connect(mapStateToProps)(Servers); diff --git a/frontend/src/containers/statistics.js b/frontend/src/containers/statistics.js index e35f3d57..261a78a9 100644 --- a/frontend/src/containers/statistics.js +++ b/frontend/src/containers/statistics.js @@ -3,51 +3,51 @@ import { connect } from 'react-redux'; import Progressbar from '../components/Progressbar/Progressbar'; const Statistics = ({ jobs }) => { - const clientStatus = { - Running: 0, - Starting: 0, - }; + const clientStatus = { + Running: 0, + Starting: 0, + }; - let hasJobSummary = true; - Object.values(jobs).forEach((job) => { + let hasJobSummary = true; + Object.values(jobs).forEach((job) => { // Guard against releases < 0.4.1 which don't have job summaries - if (job.JobSummary === null) { - hasJobSummary = false; - return; - } + if (job.JobSummary === null) { + hasJobSummary = false; + return; + } - Object.keys(job.JobSummary.Summary).forEach((taskGroup) => { - Object.keys(job.JobSummary.Summary[taskGroup]).forEach((stat) => { - if (!(stat in clientStatus)) { - clientStatus[stat] = 0; - } + Object.keys(job.JobSummary.Summary).forEach((taskGroup) => { + Object.keys(job.JobSummary.Summary[taskGroup]).forEach((stat) => { + if (!(stat in clientStatus)) { + clientStatus[stat] = 0; + } - clientStatus[stat] += job.JobSummary.Summary[taskGroup][stat]; - }); - }); + clientStatus[stat] += job.JobSummary.Summary[taskGroup][stat]; + }); }); + }); - if (!hasJobSummary) { - return
    ; - } + if (!hasJobSummary) { + return
    ; + } - delete clientStatus.Complete; + delete clientStatus.Complete; - return ( -
    -
    - -
    + return ( +
    +
    +
    - ); +
    + ); }; function mapStateToProps({ jobs }) { - return { jobs }; + return { jobs }; } Statistics.propTypes = { - jobs: PropTypes.array.isRequired, + jobs: PropTypes.array.isRequired, }; export default connect(mapStateToProps)(Statistics); diff --git a/frontend/src/helpers/time.js b/frontend/src/helpers/time.js index 7704ccad..760b09cf 100644 --- a/frontend/src/helpers/time.js +++ b/frontend/src/helpers/time.js @@ -3,19 +3,19 @@ import moment from 'moment'; const nanosecondLength = 19; function normalizeTime(time) { - const length = time.toString().length; + const length = time.toString().length; - if (length >= nanosecondLength) { - return time / 1000000; - } + if (length >= nanosecondLength) { + return time / 1000000; + } - return time; + return time; } export default function getMoment(time) { - if (time === 'now' || time === null) { - return moment(); - } + if (time === 'now' || time === null) { + return moment(); + } - return moment(normalizeTime(time), 'x'); + return moment(normalizeTime(time), 'x'); } diff --git a/frontend/src/helpers/uuid.js b/frontend/src/helpers/uuid.js index f6a287c4..70957333 100644 --- a/frontend/src/helpers/uuid.js +++ b/frontend/src/helpers/uuid.js @@ -1,5 +1,5 @@ function shortUUID(ID) { - return ID.substring(0, 8); + return ID.substring(0, 8); } export default shortUUID; diff --git a/frontend/src/main.js b/frontend/src/main.js index ee33bcdc..249ce226 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -11,12 +11,12 @@ import '../assets/css/pe-icon-7-stroke.css'; import '../assets/sass/nomad-ui.scss'; configureStore().then((store) => { - ReactDOM.render( - - - , + ReactDOM.render( + + + , document.getElementById('app') ); }).catch((err) => { - console.log(err); + console.log(err); }); diff --git a/frontend/src/reducers/allocation.js b/frontend/src/reducers/allocation.js index db20019c..f483d099 100644 --- a/frontend/src/reducers/allocation.js +++ b/frontend/src/reducers/allocation.js @@ -1,29 +1,29 @@ import { FETCHED_ALLOCS, FETCHED_ALLOC } from '../sagas/event'; export function AllocInfoReducer(state = {}, action) { - switch (action.type) { - case FETCHED_ALLOC: { - const allocation = action.payload; - allocation.TaskGroupId = `${allocation.JobID}.${allocation.TaskGroup}`; - return allocation; - } - default: - } + switch (action.type) { + case FETCHED_ALLOC: { + const allocation = action.payload; + allocation.TaskGroupId = `${allocation.JobID}.${allocation.TaskGroup}`; + return allocation; + } + default: + } - return state; + return state; } export function AllocListReducer(state = [], action) { - switch (action.type) { - case FETCHED_ALLOCS: { - const allocations = action.payload.map(allocation => + switch (action.type) { + case FETCHED_ALLOCS: { + const allocations = action.payload.map(allocation => Object.assign({}, allocation, { TaskGroupId: `${allocation.JobID}.${allocation.TaskGroup}` }) ); - return allocations; - } - default: - } + return allocations; + } + default: + } - return state; + return state; } diff --git a/frontend/src/reducers/evaluation.js b/frontend/src/reducers/evaluation.js index 1de55d54..f3ab2347 100644 --- a/frontend/src/reducers/evaluation.js +++ b/frontend/src/reducers/evaluation.js @@ -1,19 +1,19 @@ import { FETCHED_EVALS, FETCHED_EVAL } from '../sagas/event'; export function EvalInfoReducer(state = {}, action) { - switch (action.type) { - case FETCHED_EVAL: - return action.payload; - default: - } - return state; + switch (action.type) { + case FETCHED_EVAL: + return action.payload; + default: + } + return state; } export function EvalListReducer(state = [], action) { - switch (action.type) { - case FETCHED_EVALS: - return action.payload; - default: - } - return state; + switch (action.type) { + case FETCHED_EVALS: + return action.payload; + default: + } + return state; } diff --git a/frontend/src/reducers/filesystem.js b/frontend/src/reducers/filesystem.js index 7dcc72e0..f2d88476 100644 --- a/frontend/src/reducers/filesystem.js +++ b/frontend/src/reducers/filesystem.js @@ -1,23 +1,23 @@ import { FETCHED_DIR, FETCHED_FILE, CLEAR_FILE_PATH, CLEAR_RECEIVED_FILE_DATA } from '../sagas/event'; export function DirectoryReducer(state = [], action) { - switch (action.type) { - case FETCHED_DIR: - return action.payload; - default: - } - return state; + switch (action.type) { + case FETCHED_DIR: + return action.payload; + default: + } + return state; } export function FileReducer(state = { File: '' }, action) { - switch (action.type) { - case CLEAR_FILE_PATH: - return Object.assign({}, state, { File: '', Data: '' }); - case CLEAR_RECEIVED_FILE_DATA: - return Object.assign({}, state, { Data: '' }); - case FETCHED_FILE: - return action.payload; - default: - } - return state; + switch (action.type) { + case CLEAR_FILE_PATH: + return Object.assign({}, state, { File: '', Data: '' }); + case CLEAR_RECEIVED_FILE_DATA: + return Object.assign({}, state, { Data: '' }); + case FETCHED_FILE: + return action.payload; + default: + } + return state; } diff --git a/frontend/src/reducers/job.js b/frontend/src/reducers/job.js index b5252853..9e605fb1 100644 --- a/frontend/src/reducers/job.js +++ b/frontend/src/reducers/job.js @@ -1,30 +1,30 @@ import { FETCHED_JOB, FETCHED_JOBS } from '../sagas/event'; export function JobInfoReducer(state = { TaskGroups: [] }, action) { - switch (action.type) { - case FETCHED_JOB: { - const job = action.payload; - job.TaskGroups.forEach((group, gidx) => { - job.TaskGroups[gidx].ID = `${job.ID}.${group.Name}`; - }); - job.TaskGroups.forEach((group, gidx) => { - group.Tasks.forEach((task, tidx) => { - job.TaskGroups[gidx].Tasks[tidx].ID = `${group.ID}.${task.Name}`; - }); - }); - return job; - } - default: - } + switch (action.type) { + case FETCHED_JOB: { + const job = action.payload; + job.TaskGroups.forEach((group, gidx) => { + job.TaskGroups[gidx].ID = `${job.ID}.${group.Name}`; + }); + job.TaskGroups.forEach((group, gidx) => { + group.Tasks.forEach((task, tidx) => { + job.TaskGroups[gidx].Tasks[tidx].ID = `${group.ID}.${task.Name}`; + }); + }); + return job; + } + default: + } - return state; + return state; } export function JobListReducer(state = [], action) { - switch (action.type) { - case FETCHED_JOBS: - return action.payload; - default: - } - return state; + switch (action.type) { + case FETCHED_JOBS: + return action.payload; + default: + } + return state; } diff --git a/frontend/src/reducers/member.js b/frontend/src/reducers/member.js index 61360b74..a7782a39 100644 --- a/frontend/src/reducers/member.js +++ b/frontend/src/reducers/member.js @@ -1,19 +1,19 @@ import { FETCHED_MEMBERS, FETCHED_MEMBER } from '../sagas/event'; export function MemberInfoReducer(state = { Tags: {} }, action) { - switch (action.type) { - case FETCHED_MEMBER: - return action.payload; - default: - } - return state; + switch (action.type) { + case FETCHED_MEMBER: + return action.payload; + default: + } + return state; } export function MemberListReducer(state = [], action) { - switch (action.type) { - case FETCHED_MEMBERS: - return action.payload; - default: - } - return state; + switch (action.type) { + case FETCHED_MEMBERS: + return action.payload; + default: + } + return state; } diff --git a/frontend/src/reducers/node.js b/frontend/src/reducers/node.js index c764e0c4..24ff9cb5 100644 --- a/frontend/src/reducers/node.js +++ b/frontend/src/reducers/node.js @@ -1,19 +1,19 @@ import { FETCHED_NODES, FETCHED_NODE } from '../sagas/event'; export function NodeInfoReducer(state = {}, action) { - switch (action.type) { - case FETCHED_NODE: - return action.payload; - default: - } - return state; + switch (action.type) { + case FETCHED_NODE: + return action.payload; + default: + } + return state; } export function NodeListReducer(state = [], action) { - switch (action.type) { - case FETCHED_NODES: - return action.payload; - default: - } - return state; + switch (action.type) { + case FETCHED_NODES: + return action.payload; + default: + } + return state; } diff --git a/frontend/src/reducers/root.js b/frontend/src/reducers/root.js index ab64e3f9..2926074b 100644 --- a/frontend/src/reducers/root.js +++ b/frontend/src/reducers/root.js @@ -8,18 +8,18 @@ import { NodeInfoReducer, NodeListReducer } from './node'; import { DirectoryReducer, FileReducer } from './filesystem'; const rootReducer = combineReducers({ - member: MemberInfoReducer, - members: MemberListReducer, - job: JobInfoReducer, - jobs: JobListReducer, - node: NodeInfoReducer, - nodes: NodeListReducer, - allocation: AllocInfoReducer, - allocations: AllocListReducer, - evaluation: EvalInfoReducer, - evaluations: EvalListReducer, - directory: DirectoryReducer, - file: FileReducer, + member: MemberInfoReducer, + members: MemberListReducer, + job: JobInfoReducer, + jobs: JobListReducer, + node: NodeInfoReducer, + nodes: NodeListReducer, + allocation: AllocInfoReducer, + allocations: AllocListReducer, + evaluation: EvalInfoReducer, + evaluations: EvalListReducer, + directory: DirectoryReducer, + file: FileReducer, }); export default rootReducer; diff --git a/frontend/src/router.js b/frontend/src/router.js index b8303464..238b9544 100644 --- a/frontend/src/router.js +++ b/frontend/src/router.js @@ -94,7 +94,7 @@ const AppRouter = ({ history }) => ; AppRouter.propTypes = { - history: PropTypes.instanceOf(browserHistory.constructor).isRequired, + history: PropTypes.instanceOf(browserHistory.constructor).isRequired, }; export default AppRouter; diff --git a/frontend/src/sagas/event.js b/frontend/src/sagas/event.js index f8df0d03..ea75a666 100644 --- a/frontend/src/sagas/event.js +++ b/frontend/src/sagas/event.js @@ -39,100 +39,100 @@ export const CLEAR_FILE_PATH = 'CLEAR_FILE_PATH'; export const CLEAR_RECEIVED_FILE_DATA = 'CLEAR_RECEIVED_FILE_DATA'; function subscribe(socket) { - return eventChannel((emit) => { + return eventChannel((emit) => { // eslint-disable-next-line no-param-reassign - socket.onmessage = (event) => { - const data = JSON.parse(event.data); - emit({ - type: data.Type, - payload: data.Payload, - }); - }; - return () => {}; - }); + socket.onmessage = (event) => { + const data = JSON.parse(event.data); + emit({ + type: data.Type, + payload: data.Payload, + }); + }; + return () => {}; + }); } function* read(socket) { - const channel = yield call(subscribe, socket); - while (true) { - const action = yield take(channel); - yield put(action); - } + const channel = yield call(subscribe, socket); + while (true) { + const action = yield take(channel); + yield put(action); + } } function* write(socket) { - while (true) { - const action = yield take([ - WATCH_JOB, - UNWATCH_JOB, - WATCH_ALLOC, - UNWATCH_ALLOC, - WATCH_EVAL, - UNWATCH_EVAL, - WATCH_NODE, - UNWATCH_NODE, - FETCH_NODE, - WATCH_MEMBER, - UNWATCH_MEMBER, - FETCH_MEMBER, - FETCH_DIR, - WATCH_FILE, - UNWATCH_FILE, - ]); - socket.send(JSON.stringify(action)); - } + while (true) { + const action = yield take([ + WATCH_JOB, + UNWATCH_JOB, + WATCH_ALLOC, + UNWATCH_ALLOC, + WATCH_EVAL, + UNWATCH_EVAL, + WATCH_NODE, + UNWATCH_NODE, + FETCH_NODE, + WATCH_MEMBER, + UNWATCH_MEMBER, + FETCH_MEMBER, + FETCH_DIR, + WATCH_FILE, + UNWATCH_FILE, + ]); + socket.send(JSON.stringify(action)); + } } function* transport(socket) { - yield fork(read, socket); - yield fork(write, socket); + yield fork(read, socket); + yield fork(write, socket); } function connectTo(url) { - const socket = new WebSocket(url); + const socket = new WebSocket(url); - const resolver = (resolve, reject) => { - const timeout = setTimeout(() => { - reject('Unable to connect to the backend...'); - }, 2000); + const resolver = (resolve, reject) => { + const timeout = setTimeout(() => { + reject('Unable to connect to the backend...'); + }, 2000); - socket.onopen = () => { - resolve(socket); - clearTimeout(timeout); - }; + socket.onopen = () => { + resolve(socket); + clearTimeout(timeout); }; + }; - return new Promise(resolver.bind(socket)); + return new Promise(resolver.bind(socket)); } function* events(socket) { - while (true) { - yield call(transport, socket); - yield delay(5000); - } + while (true) { + yield call(transport, socket); + yield delay(5000); + } } export default function eventSaga() { - return new Promise((resolve, reject) => { - const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'; + return new Promise((resolve, reject) => { + const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'; // If we build production page, assume /ws run inside the go-binary // and such on same host+port otherwise assume development, where we // re-use the hostname but use GO_PORT end with fallback to :3000. - let hostname; - if (process.env.NODE_ENV === 'production') { - hostname = location.host; - } else { - hostname = `${location.hostname}:${process.env.GO_PORT}` || 3000; - } - - const url = `${protocol}//${hostname}/ws`; - const p = connectTo(url); - - return p.then((socket) => { - resolve(function* eventGenerator() { yield fork(events, socket); }); - }).catch((err) => { - reject(err); - }); + let hostname; + if (process.env.NODE_ENV === 'production') { + hostname = location.host; + } else { + hostname = `${location.hostname}:${process.env.GO_PORT}` || 3000; + } + + const url = `${protocol}//${hostname}/ws`; + const p = connectTo(url); + + return p.then((socket) => { + resolve(function* eventGenerator() { yield fork(events, socket); }); + }).catch((err) => { + reject(err); }); + }); } diff --git a/frontend/src/store.js b/frontend/src/store.js index 0eaf7446..d91c6c99 100644 --- a/frontend/src/store.js +++ b/frontend/src/store.js @@ -4,9 +4,9 @@ import rootReducer from './reducers/root'; import eventSaga from './sagas/event'; export default function configureStore(initialState) { - const sagaMiddleware = createSagaMiddleware(); + const sagaMiddleware = createSagaMiddleware(); - const store = createStore( + const store = createStore( rootReducer, initialState, compose( @@ -21,25 +21,25 @@ export default function configureStore(initialState) { ) ); - if (module.hot) { + if (module.hot) { // Enable Webpack hot module replacement for reducers - module.hot.accept('./reducers/root', () => { + module.hot.accept('./reducers/root', () => { // eslint-disable-next-line global-require - const nextRootReducer = require('./reducers/root').default; + const nextRootReducer = require('./reducers/root').default; - store.replaceReducer(nextRootReducer); - }); - } + store.replaceReducer(nextRootReducer); + }); + } - store.runSaga = sagaMiddleware.run; - store.close = () => store.dispatch(END); + store.runSaga = sagaMiddleware.run; + store.close = () => store.dispatch(END); - return new Promise((resolve, reject) => { - eventSaga().then((gen) => { - sagaMiddleware.run(gen); - resolve(store); - }).catch((err) => { - reject(err); - }); + return new Promise((resolve, reject) => { + eventSaga().then((gen) => { + sagaMiddleware.run(gen); + resolve(store); + }).catch((err) => { + reject(err); }); + }); } From 0b865c681d4cbe85d100400a6274da582c387de7 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 2 Dec 2016 14:50:16 +0100 Subject: [PATCH 05/45] update editor config --- frontend/.editorconfig | 49 +++++++++++++++++++ .../src/components/NomadLink/NomadLink.js | 2 +- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/frontend/.editorconfig b/frontend/.editorconfig index 0f099897..d98076ae 100644 --- a/frontend/.editorconfig +++ b/frontend/.editorconfig @@ -3,8 +3,57 @@ root = true [*] indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.json] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.js] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.scss] +indent_style = space indent_size = 2 end_of_line = lf charset = utf-8 +insert_final_newline = true trim_trailing_whitespace = true + +[*.bat] +end_of_line = crlf + +[*.yml] +indent_style = space +indent_size = 2 insert_final_newline = true +trim_trailing_whitespace = true +charset = utf-8 + +[*.yaml] +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true +charset = utf-8 + +# In a Makefile, the tab is significant and not "just" whitespace +[Makefile] +indent_style = tab +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true +charset = utf-8 diff --git a/frontend/src/components/NomadLink/NomadLink.js b/frontend/src/components/NomadLink/NomadLink.js index 28b8538c..b69473b3 100644 --- a/frontend/src/components/NomadLink/NomadLink.js +++ b/frontend/src/components/NomadLink/NomadLink.js @@ -136,7 +136,7 @@ export default class NomadLink extends Component { console.error('NomadLink: You must also provide jobId for taskGroup links!'); } - // job (must be after task & taskGroup + // job (must be after task & taskGroup if (this.props.jobId !== undefined) { const jobId = this.props.jobId; const jobIdUrl = encodeURIComponent(jobId); From 3122ac33359ba86a96139fe96a438ae0750c0764 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 2 Dec 2016 15:04:45 +0100 Subject: [PATCH 06/45] be more strict in NomadLink on errors --- .../AllocationList/AllocationList.js | 15 ++--- .../src/components/NomadLink/NomadLink.js | 60 ++++++++++--------- 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/frontend/src/components/AllocationList/AllocationList.js b/frontend/src/components/AllocationList/AllocationList.js index 3bdac2cf..874c2f97 100644 --- a/frontend/src/components/AllocationList/AllocationList.js +++ b/frontend/src/components/AllocationList/AllocationList.js @@ -24,7 +24,7 @@ const jobHeaderColumn = display => (display ? Job : null); const jobColumn = (allocation, display) => - (display ? : null); + (display ? : null); const clientHeaderColumn = display => (display ? Client : null); @@ -157,7 +157,7 @@ class AllocationList extends Component { jobs.unshift(
  • - Any -
  • - ); + ); return ( @@ -171,6 +171,7 @@ class AllocationList extends Component { const query = this.props.location.query || {}; let title = 'Client'; + if ('client' in query) { title = {title}: { this.findNodeNameById(query.client) }; } @@ -194,7 +195,7 @@ class AllocationList extends Component {
  • - Any -
  • - ); + ); return ( @@ -243,7 +244,7 @@ class AllocationList extends Component { { allocation.TaskGroup } (#{ getAllocationNumberFromName(allocation.Name) }) - +
    { renderDesiredStatus(allocation) } { clientColumn(allocation, nodes, showClientColumn) } @@ -268,13 +269,13 @@ class AllocationList extends Component { >
  • - Evaluation { shortUUID(allocation.EvalID) } + Evaluation { shortUUID(allocation.EvalID) }
  • - Files - + Files +
  • Task States diff --git a/frontend/src/components/NomadLink/NomadLink.js b/frontend/src/components/NomadLink/NomadLink.js index b69473b3..ab8ade8e 100644 --- a/frontend/src/components/NomadLink/NomadLink.js +++ b/frontend/src/components/NomadLink/NomadLink.js @@ -4,6 +4,11 @@ import shortUUID from '../../helpers/uuid'; let nodeIdToNameCache = {}; +const NomadLinkException = (message) => { + this.message = message; + this.name = 'NomadLinkException'; +}; + export default class NomadLink extends Component { componentWillReceiveProps(nextProps) { @@ -37,25 +42,28 @@ export default class NomadLink extends Component { let children = this.props.children; const linkProps = Object.assign({}, this.props); - Object.keys(linkProps).filter(key => key.endsWith('Id')).forEach((key) => { - delete linkProps[key]; - }); + Object.keys(linkProps) + .filter(key => key.endsWith('Id')) + .forEach((key) => { + delete linkProps[key]; + }); + delete linkProps.short; delete linkProps.nodeList; delete linkProps.linkAppend; - // member + // member if (this.props.memberId !== undefined) { const memberId = this.props.memberId; + if (children === undefined) { children = short ? shortUUID(memberId) : memberId; } - return ( - { children } - ); + + return ({ children }); } - // node + // node if (this.props.nodeId !== undefined) { const nodeId = this.props.nodeId; if (children === undefined) { @@ -68,35 +76,31 @@ export default class NomadLink extends Component { } } - return ( - { children } - ); + return ({ children }); } - // eval + // eval if (this.props.evalId !== undefined) { const evalId = this.props.evalId; + if (children === undefined) { children = short ? shortUUID(evalId) : evalId; } - return ( - { children } - ); + + return ({ children }); } - // alloc + // alloc if (this.props.allocId !== undefined) { const allocId = this.props.allocId; if (children === undefined) { children = short ? shortUUID(allocId) : allocId; } - return ( - { children } - ); + return ({ children }); } - // tasks + // tasks if (this.props.taskId !== undefined) { if (this.props.jobId !== undefined && this.props.taskGroupId !== undefined) { const jobId = this.props.jobId; @@ -113,10 +117,11 @@ export default class NomadLink extends Component { ); } - console.error('NomadLink: You must also provide taskGroupId and jobId for task links!'); + + throw new NomadLinkException('NomadLink: You must also provide taskGroupId and jobId for task links!'); } - // taskGroup (must be after task) + // taskGroup (must be after task) if (this.props.taskGroupId !== undefined) { if (this.props.jobId !== undefined) { const jobId = this.props.jobId; @@ -133,7 +138,8 @@ export default class NomadLink extends Component { ); } - console.error('NomadLink: You must also provide jobId for taskGroup links!'); + + throw new NomadLinkException('NomadLink: You must also provide jobId for taskGroup links!'); } // job (must be after task & taskGroup @@ -144,13 +150,11 @@ export default class NomadLink extends Component { if (children === undefined) { children = short ? shortUUID(jobId) : jobId; } - return ( - { children } - ); + + return ({ children }); } - // nothing by default - return null; + throw new NomadLinkException('NomadLink: I did not understand the props you send, unable to generate a link'); } } From 5e22f6053155cd375769020d4f483ab15f24dfbf Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 2 Dec 2016 15:30:56 +0100 Subject: [PATCH 07/45] move each allocation row into its own component --- .../AllocationList/AllocationList.js | 114 ++------------- .../AllocationListRow/AllocationListRow.js | 132 ++++++++++++++++++ 2 files changed, 141 insertions(+), 105 deletions(-) create mode 100644 frontend/src/components/AllocationListRow/AllocationListRow.js diff --git a/frontend/src/components/AllocationList/AllocationList.js b/frontend/src/components/AllocationList/AllocationList.js index 874c2f97..da19a610 100644 --- a/frontend/src/components/AllocationList/AllocationList.js +++ b/frontend/src/components/AllocationList/AllocationList.js @@ -1,67 +1,14 @@ import React, { Component, PropTypes } from 'react'; -import { DropdownButton, Glyphicon } from 'react-bootstrap'; +import { DropdownButton } from 'react-bootstrap'; import { Link } from 'react-router'; -import ReactTooltip from 'react-tooltip'; -import NomadLink from '../NomadLink/NomadLink'; -import FormatTime from '../FormatTime/FormatTime'; -import shortUUID from '../../helpers/uuid'; - -const getAllocationNumberFromName = (allocationName) => { - const match = /[\d+]/.exec(allocationName); - return match[0]; -}; - -const clientStatusIcon = { - complete: , - running: , - lost: , - failed: , -}; - -const optionsGlyph = ; +import AllocationListRow from '../AllocationListRow/AllocationListRow'; const jobHeaderColumn = display => (display ? Job : null); -const jobColumn = (allocation, display) => - (display ? : null); - const clientHeaderColumn = display => (display ? Client : null); -const clientColumn = (allocation, nodes, display) => - (display ? : null); - -const renderDesiredStatus = (allocation) => { - if (allocation.DesiredDescription) { - return ( -
    - {allocation.DesiredDescription} - - {allocation.DesiredStatus} - -
    - ); - } - - return
    {allocation.DesiredStatus}
    ; -}; - -const renderClientStatus = (allocation) => { - let icon = null; - - if (allocation.ClientStatus in clientStatusIcon) { - icon = clientStatusIcon[allocation.ClientStatus]; - } - - return ( -
    - {allocation.ClientStatus} - {icon} -
    - ); -}; - let nodeIdToNameCache = {}; class AllocationList extends Component { @@ -205,10 +152,9 @@ class AllocationList extends Component { } render() { + const props = this.props; const showJobColumn = this.props.showJobColumn; const showClientColumn = this.props.showClientColumn; - const allocations = this.props.allocations; - const nodes = this.props.nodes; const className = this.props.containerClassName; return ( @@ -235,55 +181,13 @@ class AllocationList extends Component { - {this.filteredAllocations().map((allocation, index) => { + {this.filteredAllocations().map((allocation) => { return ( - - { renderClientStatus(allocation) } - - { jobColumn(allocation, showJobColumn, nodes) } - - - { allocation.TaskGroup } (#{ getAllocationNumberFromName(allocation.Name) }) - - - { renderDesiredStatus(allocation) } - { clientColumn(allocation, nodes, showClientColumn) } - - - - - - - allocations.length - 4 } - className="btn btn-xs btn-simple pull-right" - title={ optionsGlyph } - key={ allocation.Name } - id={ `actions-${allocation.Name}` } - > -
  • - - Evaluation { shortUUID(allocation.EvalID) } - -
  • -
  • - - Files - -
  • -
  • - Task States -
  • - - - - ); + ); })} diff --git a/frontend/src/components/AllocationListRow/AllocationListRow.js b/frontend/src/components/AllocationListRow/AllocationListRow.js new file mode 100644 index 00000000..120dcca2 --- /dev/null +++ b/frontend/src/components/AllocationListRow/AllocationListRow.js @@ -0,0 +1,132 @@ +import React, { Component, PropTypes } from 'react'; +import { DropdownButton, Glyphicon } from 'react-bootstrap'; +import ReactTooltip from 'react-tooltip'; +import NomadLink from '../NomadLink/NomadLink'; +import FormatTime from '../FormatTime/FormatTime'; +import shortUUID from '../../helpers/uuid'; + +const optionsGlyph = ; + +const clientStatusIcon = { + complete: , + running: , + lost: , + failed: , +}; + +const getAllocationNumberFromName = (allocationName) => { + const match = /[\d+]/.exec(allocationName); + return match[0]; +}; + +const renderClientStatus = (allocation) => { + let icon = null; + + if (allocation.ClientStatus in clientStatusIcon) { + icon = clientStatusIcon[allocation.ClientStatus]; + } + + return ( +
    + {allocation.ClientStatus} + {icon} +
    + ); +}; + +const jobColumn = (allocation, display) => + (display ? : null); + +const clientColumn = (allocation, nodes, display) => + (display ? : null); + +const renderDesiredStatus = (allocation) => { + if (allocation.DesiredDescription) { + return ( +
    + {allocation.DesiredDescription} + + {allocation.DesiredStatus} + +
    + ); + } + + return
    {allocation.DesiredStatus}
    ; +}; + +class AllocationListRow extends Component { + + render() { + const allocation = this.props.allocation; + const nodes = this.props.nodes; + const showJobColumn = this.props.showJobColumn; + const showClientColumn = this.props.showClientColumn; + + return ( + + { renderClientStatus(allocation) } + + { jobColumn(allocation, showJobColumn, nodes) } + + + { allocation.TaskGroup } (#{ getAllocationNumberFromName(allocation.Name) }) + + + { renderDesiredStatus(allocation) } + { clientColumn(allocation, nodes, showClientColumn) } + + + + + + + +
  • + + Evaluation { shortUUID(allocation.EvalID) } + +
  • +
  • + + Files + +
  • +
  • + Task States +
  • +
    + + + ); + } +} + +AllocationListRow.defaultProps = { + allocations: [], + nodes: [], + + showJobColumn: true, + showClientColumn: true, +}; + +AllocationListRow.propTypes = { + allocation: PropTypes.object.isRequired, + nodes: PropTypes.array.isRequired, + + showJobColumn: PropTypes.bool.isRequired, + showClientColumn: PropTypes.bool.isRequired, +}; + +export default AllocationListRow; From ebf869ec32a25718c78d33fce57eeaac61935082 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 2 Dec 2016 15:31:57 +0100 Subject: [PATCH 08/45] inline rendering of AllocationListRow --- frontend/src/components/AllocationList/AllocationList.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/frontend/src/components/AllocationList/AllocationList.js b/frontend/src/components/AllocationList/AllocationList.js index da19a610..14a1f2ad 100644 --- a/frontend/src/components/AllocationList/AllocationList.js +++ b/frontend/src/components/AllocationList/AllocationList.js @@ -182,12 +182,7 @@ class AllocationList extends Component { {this.filteredAllocations().map((allocation) => { - return ( - ); + return ; })} From bf175c6183fe8009579b1dfa0d478a56d4c1440e Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 2 Dec 2016 15:45:29 +0100 Subject: [PATCH 09/45] add react-optimize as a preset --- frontend/config/babel.prod.js | 3 ++- frontend/package.json | 1 + frontend/webpack.config.js | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/config/babel.prod.js b/frontend/config/babel.prod.js index 121dc96b..51a2a339 100644 --- a/frontend/config/babel.prod.js +++ b/frontend/config/babel.prod.js @@ -2,7 +2,8 @@ module.exports = { presets: [ 'babel-preset-es2015', 'babel-preset-es2016', - 'babel-preset-react' + 'babel-preset-react', + 'react-optimize' ].map(require.resolve), plugins: [ 'babel-plugin-transform-runtime', diff --git a/frontend/package.json b/frontend/package.json index 5dd9a0d4..380e968e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -53,6 +53,7 @@ "babel-preset-es2015": "^6.9.0", "babel-preset-es2016": "^6.11.3", "babel-preset-react": "^6.11.1", + "babel-preset-react-optimize": "^1.0.1", "css-loader": "^0.23.1", "eslint": "^3.7.0", "eslint-config-airbnb": "^12.0.0", diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js index 7125b957..e9b705ab 100644 --- a/frontend/webpack.config.js +++ b/frontend/webpack.config.js @@ -43,7 +43,7 @@ webpackConfig = merge(webpackConfig, { exclude: /node_modules/, loaders: [ 'react-hot', - 'babel?presets[]=es2015,presets[]=es2016,presets[]=react,plugins[]=syntax-trailing-function-commas,plugins[]=transform-runtime,plugins[]=transform-class-properties,plugins[]=transform-object-rest-spread' + 'babel?presets[]=es2015&presets[]=es2016&presets[]=react&presets[]=react-optimize&plugins[]=transform-react-inline-elements&plugins[]=syntax-trailing-function-commas&plugins[]=transform-runtime&plugins[]=transform-class-properties&plugins[]=transform-object-rest-spread' ] }, { From 4c2db30cb78e068ec0d33bdcfa1cdc28b474ee87 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 2 Dec 2016 15:46:24 +0100 Subject: [PATCH 10/45] don't short job id --- frontend/src/containers/jobs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/containers/jobs.js b/frontend/src/containers/jobs.js index 82c04288..1c8e9e6a 100644 --- a/frontend/src/containers/jobs.js +++ b/frontend/src/containers/jobs.js @@ -146,7 +146,7 @@ class Jobs extends Component { { this.filteredJobs().map(job => - + { job.Status } { job.Type } { job.Priority } From bdf80470a0717d87a666143c68f46739701437de Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 2 Dec 2016 16:04:58 +0100 Subject: [PATCH 11/45] dont generate uuid for each time tooltip, but rely on the parent to provide unique identifier --- .../components/AllocationListRow/AllocationListRow.js | 2 +- frontend/src/components/FormatTime/FormatTime.js | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/AllocationListRow/AllocationListRow.js b/frontend/src/components/AllocationListRow/AllocationListRow.js index 120dcca2..fc2833a7 100644 --- a/frontend/src/components/AllocationListRow/AllocationListRow.js +++ b/frontend/src/components/AllocationListRow/AllocationListRow.js @@ -75,7 +75,7 @@ class AllocationListRow extends Component { { renderDesiredStatus(allocation) } { clientColumn(allocation, nodes, showClientColumn) } - + - { time.format(format) } - + { time.format(format) } + {this.getTimeDiff(time, now)} @@ -37,8 +35,8 @@ class FormatTime extends Component { return ( - { this.getTimeDiff(time, now) } - { time.format(format) } + { this.getTimeDiff(time, now) } + { time.format(format) } ); } @@ -59,6 +57,7 @@ FormatTime.propTypes = { PropTypes.string, PropTypes.number, ]), + identifier: PropTypes.string.isRequired, display: PropTypes.string.isRequired, timeFormat: PropTypes.string.isRequired, durationInterval: PropTypes.string, From e00a49695c29b75246e25b2d8d14000d582e87c9 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 2 Dec 2016 16:15:36 +0100 Subject: [PATCH 12/45] more fixes to rendering perf --- .../src/components/AllocationInfo/AllocationInfo.js | 10 +++++++++- frontend/src/components/NomadLink/NomadLink.js | 7 ++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/AllocationInfo/AllocationInfo.js b/frontend/src/components/AllocationInfo/AllocationInfo.js index 682a9c84..b6f0d89b 100644 --- a/frontend/src/components/AllocationInfo/AllocationInfo.js +++ b/frontend/src/components/AllocationInfo/AllocationInfo.js @@ -51,6 +51,7 @@ class AllocationInfo extends Component { @@ -97,12 +98,19 @@ class AllocationInfo extends Component { return null; }); + // don't render anything big until we got the allocation from the API + if (!jobId) { + return
    Loading ...
    ; + } + allocValues.Job = ; + allocValues.TaskGroup = ( {allocation.TaskGroup} - ); + ); + allocValues.Node = ; const states = []; diff --git a/frontend/src/components/NomadLink/NomadLink.js b/frontend/src/components/NomadLink/NomadLink.js index ab8ade8e..f4a8d9e8 100644 --- a/frontend/src/components/NomadLink/NomadLink.js +++ b/frontend/src/components/NomadLink/NomadLink.js @@ -4,10 +4,10 @@ import shortUUID from '../../helpers/uuid'; let nodeIdToNameCache = {}; -const NomadLinkException = (message) => { +function NomadLinkException(message) { this.message = message; this.name = 'NomadLinkException'; -}; +} export default class NomadLink extends Component { @@ -154,7 +154,8 @@ export default class NomadLink extends Component { return ({ children }); } - throw new NomadLinkException('NomadLink: I did not understand the props you send, unable to generate a link'); + console.log(this.props); + throw new NomadLinkException('NomadLink: Unable to generate a link (check console for props)'); } } From 56c9c41a885758ef98c38e50fd526c4648f8b7ae Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 2 Dec 2016 16:32:08 +0100 Subject: [PATCH 13/45] significantly improve allocation list rendering performance --- frontend/package.json | 1 + .../AllocationListRow/AllocationListRow.js | 28 +------------------ .../src/components/NomadLink/NomadLink.js | 8 +----- frontend/src/main.js | 5 ++++ 4 files changed, 8 insertions(+), 34 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 380e968e..8047d782 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -31,6 +31,7 @@ "moment-duration-format": "^1.3.0", "node-uuid": "^1.4.7", "react": "^15.4.1", + "react-addons-perf": "^15.4.1", "react-bootstrap": "^0.30.7", "react-dom": "^15.4.1", "react-redux": "^4.4.6", diff --git a/frontend/src/components/AllocationListRow/AllocationListRow.js b/frontend/src/components/AllocationListRow/AllocationListRow.js index fc2833a7..082cf83e 100644 --- a/frontend/src/components/AllocationListRow/AllocationListRow.js +++ b/frontend/src/components/AllocationListRow/AllocationListRow.js @@ -1,11 +1,8 @@ import React, { Component, PropTypes } from 'react'; -import { DropdownButton, Glyphicon } from 'react-bootstrap'; +import { Glyphicon } from 'react-bootstrap'; import ReactTooltip from 'react-tooltip'; import NomadLink from '../NomadLink/NomadLink'; import FormatTime from '../FormatTime/FormatTime'; -import shortUUID from '../../helpers/uuid'; - -const optionsGlyph = ; const clientStatusIcon = { complete: , @@ -84,29 +81,6 @@ class AllocationListRow extends Component { > - - -
  • - - Evaluation { shortUUID(allocation.EvalID) } - -
  • -
  • - - Files - -
  • -
  • - Task States -
  • -
    ); diff --git a/frontend/src/components/NomadLink/NomadLink.js b/frontend/src/components/NomadLink/NomadLink.js index f4a8d9e8..48e5ca11 100644 --- a/frontend/src/components/NomadLink/NomadLink.js +++ b/frontend/src/components/NomadLink/NomadLink.js @@ -2,7 +2,7 @@ import React, { Component, PropTypes } from 'react'; import { Link } from 'react-router'; import shortUUID from '../../helpers/uuid'; -let nodeIdToNameCache = {}; +const nodeIdToNameCache = {}; function NomadLinkException(message) { this.message = message; @@ -11,12 +11,6 @@ function NomadLinkException(message) { export default class NomadLink extends Component { - componentWillReceiveProps(nextProps) { - if (nextProps.nodeList !== this.props.nodeList) { - nodeIdToNameCache = {}; - } - } - findNodeNameById(nodeId) { if (nodeId in nodeIdToNameCache) { return nodeIdToNameCache[nodeId]; diff --git a/frontend/src/main.js b/frontend/src/main.js index 249ce226..414cbacc 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -2,6 +2,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { browserHistory } from 'react-router'; import { Provider } from 'react-redux'; +import Perf from 'react-addons-perf'; import 'bootstrap/dist/css/bootstrap.min.css'; import AppRouter from './router'; @@ -10,6 +11,8 @@ import configureStore from './store'; import '../assets/css/pe-icon-7-stroke.css'; import '../assets/sass/nomad-ui.scss'; +Perf.start(); + configureStore().then((store) => { ReactDOM.render( @@ -20,3 +23,5 @@ configureStore().then((store) => { }).catch((err) => { console.log(err); }); + +window.Perf = Perf; From 6ff18b0af6e8ae43918ec04ba3c0520941a2d5e9 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 2 Dec 2016 16:36:32 +0100 Subject: [PATCH 14/45] cleanup perf --- frontend/src/main.js | 6 +++--- frontend/webpack-prod.config.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/main.js b/frontend/src/main.js index 414cbacc..c494c1d7 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -2,7 +2,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { browserHistory } from 'react-router'; import { Provider } from 'react-redux'; -import Perf from 'react-addons-perf'; +// import Perf from 'react-addons-perf'; import 'bootstrap/dist/css/bootstrap.min.css'; import AppRouter from './router'; @@ -11,7 +11,7 @@ import configureStore from './store'; import '../assets/css/pe-icon-7-stroke.css'; import '../assets/sass/nomad-ui.scss'; -Perf.start(); +// Perf.start(); configureStore().then((store) => { ReactDOM.render( @@ -24,4 +24,4 @@ configureStore().then((store) => { console.log(err); }); -window.Perf = Perf; +// window.Perf = Perf; diff --git a/frontend/webpack-prod.config.js b/frontend/webpack-prod.config.js index cef624ed..e577c149 100644 --- a/frontend/webpack-prod.config.js +++ b/frontend/webpack-prod.config.js @@ -42,10 +42,10 @@ webpackConfig = merge(webpackConfig, { ] }, plugins: [ + new webpack.DefinePlugin({'process.env.NODE_ENV': '"production"'}), new ExtractTextPlugin('static/[name].[contenthash].css'), new webpack.optimize.OccurenceOrderPlugin(), new webpack.optimize.DedupePlugin(), - new webpack.DefinePlugin({'process.env.NODE_ENV': '"production"'}), new webpack.optimize.UglifyJsPlugin({ compressor: { screw_ie8: true, From 30fd1e7b61c42a5e13079f2314a86ea61fea6ab6 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 2 Dec 2016 16:46:21 +0100 Subject: [PATCH 15/45] build and publish PR --- .travis.yml | 1 + frontend/config/babel.prod.js | 3 ++- frontend/webpack-prod.config.js | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a6d54080..e9c7a35a 100755 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,7 @@ script: after_success: - export PR=https://api.github.com/repos/$TRAVIS_REPO_SLUG/pulls/$TRAVIS_PULL_REQUEST - export BRANCH=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; else echo `curl -s $PR | jq -r .head.ref`; fi) + - if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then make docker DOCKER_USER=$DOCKER_USER DOCKER_PASS=$DOCKER_PASS DOCKER_EMAIL=$DOCKER_EMAIL TAG=pr-$TRAVIS_PULL_REQUEST COMMIT=$TRAVIS_COMMIT; fi - if [[ "$TRAVIS_TAG" =~ ^v.*$ ]]; then make docker DOCKER_USER=$DOCKER_USER DOCKER_PASS=$DOCKER_PASS DOCKER_EMAIL=$DOCKER_EMAIL TAG=$TRAVIS_TAG COMMIT=$TRAVIS_COMMIT; fi - if [[ "$BRANCH" == "master" ]]; then make docker DOCKER_USER=$DOCKER_USER DOCKER_PASS=$DOCKER_PASS DOCKER_EMAIL=$DOCKER_EMAIL TAG=latest COMMIT=$TRAVIS_COMMIT; fi diff --git a/frontend/config/babel.prod.js b/frontend/config/babel.prod.js index 51a2a339..67916793 100644 --- a/frontend/config/babel.prod.js +++ b/frontend/config/babel.prod.js @@ -3,8 +3,9 @@ module.exports = { 'babel-preset-es2015', 'babel-preset-es2016', 'babel-preset-react', - 'react-optimize' + 'babel-preset-react-optimize' ].map(require.resolve), + plugins: [ 'babel-plugin-transform-runtime', 'babel-plugin-syntax-trailing-function-commas', diff --git a/frontend/webpack-prod.config.js b/frontend/webpack-prod.config.js index e577c149..ba9155b4 100644 --- a/frontend/webpack-prod.config.js +++ b/frontend/webpack-prod.config.js @@ -6,6 +6,7 @@ const ExtractTextPlugin = require("extract-text-webpack-plugin"); const HtmlWebpackPlugin = require('html-webpack-plugin'); var webpackConfig = require("./webpack-base.config.js"); + webpackConfig = merge(webpackConfig, { output: { filename: 'static/[name].[chunkhash].js', From 680ae91cc87ef8fcfa391331751730107fe17232 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Mon, 5 Dec 2016 10:52:58 +0100 Subject: [PATCH 16/45] remove existing css and further refactor the ui --- frontend/assets/css/animate.min.css | 6 - frontend/assets/css/dashboard.css | 2781 ----------------- frontend/assets/css/font-awesome.min.css | 4 - frontend/assets/css/fonts.css | 18 - frontend/assets/css/pe-icon-7-stroke.css | 632 ---- frontend/assets/fonts/Pe-icon-7-stroke.eot | Bin 58680 -> 0 bytes frontend/assets/fonts/Pe-icon-7-stroke.svg | 212 -- frontend/assets/fonts/Pe-icon-7-stroke.ttf | Bin 58480 -> 0 bytes frontend/assets/fonts/Pe-icon-7-stroke.woff | Bin 58556 -> 0 bytes frontend/assets/img/mask.png | Bin 756 -> 0 bytes frontend/assets/img/nomad.jpg | Bin 437643 -> 0 bytes frontend/assets/nomad-ui.css | 22 + frontend/assets/sass/nomad-ui.scss | 185 -- frontend/assets/sass/nomad-ui/_alerts.scss | 82 - frontend/assets/sass/nomad-ui/_buttons.scss | 123 - frontend/assets/sass/nomad-ui/_cards.scss | 322 -- frontend/assets/sass/nomad-ui/_carousel.scss | 15 - .../sass/nomad-ui/_checkbox-radio-switch.scss | 253 -- frontend/assets/sass/nomad-ui/_collapse.scss | 49 - frontend/assets/sass/nomad-ui/_dropdown.scss | 176 -- frontend/assets/sass/nomad-ui/_footers.scss | 155 - frontend/assets/sass/nomad-ui/_forms.scss | 41 - frontend/assets/sass/nomad-ui/_inputs.scss | 170 - frontend/assets/sass/nomad-ui/_labels.scss | 54 - frontend/assets/sass/nomad-ui/_media.scss | 80 - frontend/assets/sass/nomad-ui/_misc.scss | 87 - frontend/assets/sass/nomad-ui/_mixins.scss | 22 - frontend/assets/sass/nomad-ui/_modal.scss | 79 - frontend/assets/sass/nomad-ui/_navbars.scss | 362 --- frontend/assets/sass/nomad-ui/_pages.scss | 215 -- .../assets/sass/nomad-ui/_progress-bars.scss | 26 - .../assets/sass/nomad-ui/_responsive.scss | 688 ---- .../nomad-ui/_sidebar-and-main-panel.scss | 575 ---- frontend/assets/sass/nomad-ui/_sliders.scss | 219 -- .../assets/sass/nomad-ui/_social-buttons.scss | 77 - frontend/assets/sass/nomad-ui/_tables.scss | 120 - .../sass/nomad-ui/_tabs-navs-pagination.scss | 302 -- frontend/assets/sass/nomad-ui/_tags.scss | 123 - .../sass/nomad-ui/_tooltips-and-popovers.scss | 156 - .../assets/sass/nomad-ui/_typography.scss | 93 - frontend/assets/sass/nomad-ui/_variables.scss | 320 -- .../assets/sass/nomad-ui/mixins/_buttons.scss | 74 - .../assets/sass/nomad-ui/mixins/_cards.scss | 8 - .../sass/nomad-ui/mixins/_chartist.scss | 85 - .../assets/sass/nomad-ui/mixins/_icons.scss | 13 - .../assets/sass/nomad-ui/mixins/_inputs.scss | 17 - .../assets/sass/nomad-ui/mixins/_labels.scss | 21 - .../nomad-ui/mixins/_morphing-buttons.scss | 34 - .../assets/sass/nomad-ui/mixins/_navbars.scss | 11 - .../sass/nomad-ui/mixins/_social-buttons.scss | 43 - .../sass/nomad-ui/mixins/_table-row.scss | 22 - .../assets/sass/nomad-ui/mixins/_tabs.scss | 4 - .../sass/nomad-ui/mixins/_transparency.scss | 20 - .../nomad-ui/mixins/_vendor-prefixes.scss | 197 -- .../sass/nomad-ui/plugins/_animate.scss | 228 -- .../nomad-ui/plugins/_bootstrap-select.scss | 308 -- .../nomad-ui/plugins/_bootstrap-table.scss | 328 -- .../sass/nomad-ui/plugins/_chartist.scss | 247 -- .../sass/nomad-ui/plugins/_datatable.scss | 328 -- .../nomad-ui/plugins/_datatables.net.scss | 513 --- .../nomad-ui/plugins/_datetime-picker.scss | 440 --- .../sass/nomad-ui/plugins/_fullcalendar.scss | 1114 ------- .../nomad-ui/plugins/_jquery.jvectormap.scss | 135 - .../nomad-ui/plugins/_perfect-scrollbar.scss | 111 - .../sass/nomad-ui/plugins/_sweetalert2.scss | 531 ---- frontend/index.html.ejs | 37 +- frontend/package.json | 2 + .../AllocationFiles/AllocationFiles.js | 4 +- .../AllocationList/AllocationList.js | 88 +- .../AllocationListRow/AllocationListRow.js | 21 +- frontend/src/components/JobInfo/JobInfo.js | 6 +- .../components/JobTaskGroups/JobTaskGroups.js | 4 +- frontend/src/components/JobTasks/JobTasks.js | 4 +- .../src/components/ServerInfo/ServerInfo.js | 4 +- frontend/src/components/Sidebar/Sidebar.js | 80 - frontend/src/components/Table/Table.js | 23 - .../src/components/TableHelper/TableHelper.js | 22 + frontend/src/components/Topbar/Topbar.js | 75 +- frontend/src/components/app.js | 38 +- frontend/src/containers/allocations.js | 18 +- frontend/src/main.js | 7 +- frontend/webpack-base.config.js | 25 +- frontend/webpack.config.js | 10 +- 83 files changed, 221 insertions(+), 13923 deletions(-) delete mode 100755 frontend/assets/css/animate.min.css delete mode 100644 frontend/assets/css/dashboard.css delete mode 100644 frontend/assets/css/font-awesome.min.css delete mode 100644 frontend/assets/css/fonts.css delete mode 100755 frontend/assets/css/pe-icon-7-stroke.css delete mode 100755 frontend/assets/fonts/Pe-icon-7-stroke.eot delete mode 100755 frontend/assets/fonts/Pe-icon-7-stroke.svg delete mode 100755 frontend/assets/fonts/Pe-icon-7-stroke.ttf delete mode 100755 frontend/assets/fonts/Pe-icon-7-stroke.woff delete mode 100755 frontend/assets/img/mask.png delete mode 100644 frontend/assets/img/nomad.jpg create mode 100644 frontend/assets/nomad-ui.css delete mode 100755 frontend/assets/sass/nomad-ui.scss delete mode 100644 frontend/assets/sass/nomad-ui/_alerts.scss delete mode 100755 frontend/assets/sass/nomad-ui/_buttons.scss delete mode 100644 frontend/assets/sass/nomad-ui/_cards.scss delete mode 100644 frontend/assets/sass/nomad-ui/_carousel.scss delete mode 100644 frontend/assets/sass/nomad-ui/_checkbox-radio-switch.scss delete mode 100644 frontend/assets/sass/nomad-ui/_collapse.scss delete mode 100644 frontend/assets/sass/nomad-ui/_dropdown.scss delete mode 100644 frontend/assets/sass/nomad-ui/_footers.scss delete mode 100644 frontend/assets/sass/nomad-ui/_forms.scss delete mode 100755 frontend/assets/sass/nomad-ui/_inputs.scss delete mode 100644 frontend/assets/sass/nomad-ui/_labels.scss delete mode 100644 frontend/assets/sass/nomad-ui/_media.scss delete mode 100755 frontend/assets/sass/nomad-ui/_misc.scss delete mode 100644 frontend/assets/sass/nomad-ui/_mixins.scss delete mode 100644 frontend/assets/sass/nomad-ui/_modal.scss delete mode 100644 frontend/assets/sass/nomad-ui/_navbars.scss delete mode 100644 frontend/assets/sass/nomad-ui/_pages.scss delete mode 100644 frontend/assets/sass/nomad-ui/_progress-bars.scss delete mode 100644 frontend/assets/sass/nomad-ui/_responsive.scss delete mode 100755 frontend/assets/sass/nomad-ui/_sidebar-and-main-panel.scss delete mode 100644 frontend/assets/sass/nomad-ui/_sliders.scss delete mode 100644 frontend/assets/sass/nomad-ui/_social-buttons.scss delete mode 100644 frontend/assets/sass/nomad-ui/_tables.scss delete mode 100644 frontend/assets/sass/nomad-ui/_tabs-navs-pagination.scss delete mode 100644 frontend/assets/sass/nomad-ui/_tags.scss delete mode 100644 frontend/assets/sass/nomad-ui/_tooltips-and-popovers.scss delete mode 100644 frontend/assets/sass/nomad-ui/_typography.scss delete mode 100644 frontend/assets/sass/nomad-ui/_variables.scss delete mode 100644 frontend/assets/sass/nomad-ui/mixins/_buttons.scss delete mode 100644 frontend/assets/sass/nomad-ui/mixins/_cards.scss delete mode 100644 frontend/assets/sass/nomad-ui/mixins/_chartist.scss delete mode 100644 frontend/assets/sass/nomad-ui/mixins/_icons.scss delete mode 100644 frontend/assets/sass/nomad-ui/mixins/_inputs.scss delete mode 100644 frontend/assets/sass/nomad-ui/mixins/_labels.scss delete mode 100644 frontend/assets/sass/nomad-ui/mixins/_morphing-buttons.scss delete mode 100644 frontend/assets/sass/nomad-ui/mixins/_navbars.scss delete mode 100644 frontend/assets/sass/nomad-ui/mixins/_social-buttons.scss delete mode 100644 frontend/assets/sass/nomad-ui/mixins/_table-row.scss delete mode 100644 frontend/assets/sass/nomad-ui/mixins/_tabs.scss delete mode 100644 frontend/assets/sass/nomad-ui/mixins/_transparency.scss delete mode 100644 frontend/assets/sass/nomad-ui/mixins/_vendor-prefixes.scss delete mode 100644 frontend/assets/sass/nomad-ui/plugins/_animate.scss delete mode 100644 frontend/assets/sass/nomad-ui/plugins/_bootstrap-select.scss delete mode 100644 frontend/assets/sass/nomad-ui/plugins/_bootstrap-table.scss delete mode 100644 frontend/assets/sass/nomad-ui/plugins/_chartist.scss delete mode 100644 frontend/assets/sass/nomad-ui/plugins/_datatable.scss delete mode 100644 frontend/assets/sass/nomad-ui/plugins/_datatables.net.scss delete mode 100644 frontend/assets/sass/nomad-ui/plugins/_datetime-picker.scss delete mode 100644 frontend/assets/sass/nomad-ui/plugins/_fullcalendar.scss delete mode 100644 frontend/assets/sass/nomad-ui/plugins/_jquery.jvectormap.scss delete mode 100644 frontend/assets/sass/nomad-ui/plugins/_perfect-scrollbar.scss delete mode 100644 frontend/assets/sass/nomad-ui/plugins/_sweetalert2.scss delete mode 100644 frontend/src/components/Sidebar/Sidebar.js delete mode 100644 frontend/src/components/Table/Table.js create mode 100644 frontend/src/components/TableHelper/TableHelper.js diff --git a/frontend/assets/css/animate.min.css b/frontend/assets/css/animate.min.css deleted file mode 100755 index 0b6a47de..00000000 --- a/frontend/assets/css/animate.min.css +++ /dev/null @@ -1,6 +0,0 @@ -@charset "UTF-8";/*! -Animate.css - http://daneden.me/animate -Licensed under the MIT license - http://opensource.org/licenses/MIT - -Copyright (c) 2015 Daniel Eden -*/.animated{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.animated.infinite{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.animated.hinge{-webkit-animation-duration:2s;animation-duration:2s}.animated.bounceIn,.animated.bounceOut,.animated.flipOutX,.animated.flipOutY{-webkit-animation-duration:.75s;animation-duration:.75s}@-webkit-keyframes bounce{100%,20%,53%,80%,from{-webkit-animation-timing-function:cubic-bezier(0.215,.61,.355,1);animation-timing-function:cubic-bezier(0.215,.61,.355,1);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}40%,43%{-webkit-animation-timing-function:cubic-bezier(0.755,.050,.855,.060);animation-timing-function:cubic-bezier(0.755,.050,.855,.060);-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}70%{-webkit-animation-timing-function:cubic-bezier(0.755,.050,.855,.060);animation-timing-function:cubic-bezier(0.755,.050,.855,.060);-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}@keyframes bounce{100%,20%,53%,80%,from{-webkit-animation-timing-function:cubic-bezier(0.215,.61,.355,1);animation-timing-function:cubic-bezier(0.215,.61,.355,1);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}40%,43%{-webkit-animation-timing-function:cubic-bezier(0.755,.050,.855,.060);animation-timing-function:cubic-bezier(0.755,.050,.855,.060);-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}70%{-webkit-animation-timing-function:cubic-bezier(0.755,.050,.855,.060);animation-timing-function:cubic-bezier(0.755,.050,.855,.060);-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}.bounce{-webkit-animation-name:bounce;animation-name:bounce;-webkit-transform-origin:center bottom;transform-origin:center bottom}@-webkit-keyframes flash{100%,50%,from{opacity:1}25%,75%{opacity:0}}@keyframes flash{100%,50%,from{opacity:1}25%,75%{opacity:0}}.flash{-webkit-animation-name:flash;animation-name:flash}@-webkit-keyframes pulse{from{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes pulse{from{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.pulse{-webkit-animation-name:pulse;animation-name:pulse}@-webkit-keyframes rubberBand{from{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(0.75,1.25,1);transform:scale3d(0.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes rubberBand{from{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(0.75,1.25,1);transform:scale3d(0.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.rubberBand{-webkit-animation-name:rubberBand;animation-name:rubberBand}@-webkit-keyframes shake{100%,from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}@keyframes shake{100%,from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}.shake{-webkit-animation-name:shake;animation-name:shake}@-webkit-keyframes swing{20%{-webkit-transform:rotate3d(0,0,1,15deg);transform:rotate3d(0,0,1,15deg)}40%{-webkit-transform:rotate3d(0,0,1,-10deg);transform:rotate3d(0,0,1,-10deg)}60%{-webkit-transform:rotate3d(0,0,1,5deg);transform:rotate3d(0,0,1,5deg)}80%{-webkit-transform:rotate3d(0,0,1,-5deg);transform:rotate3d(0,0,1,-5deg)}100%{-webkit-transform:rotate3d(0,0,1,0deg);transform:rotate3d(0,0,1,0deg)}}@keyframes swing{20%{-webkit-transform:rotate3d(0,0,1,15deg);transform:rotate3d(0,0,1,15deg)}40%{-webkit-transform:rotate3d(0,0,1,-10deg);transform:rotate3d(0,0,1,-10deg)}60%{-webkit-transform:rotate3d(0,0,1,5deg);transform:rotate3d(0,0,1,5deg)}80%{-webkit-transform:rotate3d(0,0,1,-5deg);transform:rotate3d(0,0,1,-5deg)}100%{-webkit-transform:rotate3d(0,0,1,0deg);transform:rotate3d(0,0,1,0deg)}}.swing{-webkit-transform-origin:top center;transform-origin:top center;-webkit-animation-name:swing;animation-name:swing}@-webkit-keyframes tada{from{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg);transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes tada{from{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg);transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.tada{-webkit-animation-name:tada;animation-name:tada}@-webkit-keyframes wobble{from{-webkit-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg);transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg);transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg);transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg);transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg);transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg)}100%{-webkit-transform:none;transform:none}}@keyframes wobble{from{-webkit-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg);transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg);transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg);transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg);transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg);transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg)}100%{-webkit-transform:none;transform:none}}.wobble{-webkit-animation-name:wobble;animation-name:wobble}@-webkit-keyframes jello{100%,11.1%,from{-webkit-transform:none;transform:none}22.2%{-webkit-transform:skewX(-12.5deg) skewY(-12.5deg);transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{-webkit-transform:skewX(6.25deg) skewY(6.25deg);transform:skewX(6.25deg) skewY(6.25deg)}44.4%{-webkit-transform:skewX(-3.125deg) skewY(-3.125deg);transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{-webkit-transform:skewX(1.5625deg) skewY(1.5625deg);transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{-webkit-transform:skewX(-.78125deg) skewY(-.78125deg);transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{-webkit-transform:skewX(0.390625deg) skewY(0.390625deg);transform:skewX(0.390625deg) skewY(0.390625deg)}88.8%{-webkit-transform:skewX(-.1953125deg) skewY(-.1953125deg);transform:skewX(-.1953125deg) skewY(-.1953125deg)}}@keyframes jello{100%,11.1%,from{-webkit-transform:none;transform:none}22.2%{-webkit-transform:skewX(-12.5deg) skewY(-12.5deg);transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{-webkit-transform:skewX(6.25deg) skewY(6.25deg);transform:skewX(6.25deg) skewY(6.25deg)}44.4%{-webkit-transform:skewX(-3.125deg) skewY(-3.125deg);transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{-webkit-transform:skewX(1.5625deg) skewY(1.5625deg);transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{-webkit-transform:skewX(-.78125deg) skewY(-.78125deg);transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{-webkit-transform:skewX(0.390625deg) skewY(0.390625deg);transform:skewX(0.390625deg) skewY(0.390625deg)}88.8%{-webkit-transform:skewX(-.1953125deg) skewY(-.1953125deg);transform:skewX(-.1953125deg) skewY(-.1953125deg)}}.jello{-webkit-animation-name:jello;animation-name:jello;-webkit-transform-origin:center;transform-origin:center}@-webkit-keyframes bounceIn{100%,20%,40%,60%,80%,from{-webkit-animation-timing-function:cubic-bezier(0.215,.61,.355,1);animation-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}100%{opacity:1;-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes bounceIn{100%,20%,40%,60%,80%,from{-webkit-animation-timing-function:cubic-bezier(0.215,.61,.355,1);animation-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}100%{opacity:1;-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.bounceIn{-webkit-animation-name:bounceIn;animation-name:bounceIn}@-webkit-keyframes bounceInDown{100%,60%,75%,90%,from{-webkit-animation-timing-function:cubic-bezier(0.215,.61,.355,1);animation-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}100%{-webkit-transform:none;transform:none}}@keyframes bounceInDown{100%,60%,75%,90%,from{-webkit-animation-timing-function:cubic-bezier(0.215,.61,.355,1);animation-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}100%{-webkit-transform:none;transform:none}}.bounceInDown{-webkit-animation-name:bounceInDown;animation-name:bounceInDown}@-webkit-keyframes bounceInLeft{100%,60%,75%,90%,from{-webkit-animation-timing-function:cubic-bezier(0.215,.61,.355,1);animation-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}100%{-webkit-transform:none;transform:none}}@keyframes bounceInLeft{100%,60%,75%,90%,from{-webkit-animation-timing-function:cubic-bezier(0.215,.61,.355,1);animation-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}100%{-webkit-transform:none;transform:none}}.bounceInLeft{-webkit-animation-name:bounceInLeft;animation-name:bounceInLeft}@-webkit-keyframes bounceInRight{100%,60%,75%,90%,from{-webkit-animation-timing-function:cubic-bezier(0.215,.61,.355,1);animation-timing-function:cubic-bezier(0.215,.61,.355,1)}from{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}100%{-webkit-transform:none;transform:none}}@keyframes bounceInRight{100%,60%,75%,90%,from{-webkit-animation-timing-function:cubic-bezier(0.215,.61,.355,1);animation-timing-function:cubic-bezier(0.215,.61,.355,1)}from{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}100%{-webkit-transform:none;transform:none}}.bounceInRight{-webkit-animation-name:bounceInRight;animation-name:bounceInRight}@-webkit-keyframes bounceInUp{100%,60%,75%,90%,from{-webkit-animation-timing-function:cubic-bezier(0.215,.61,.355,1);animation-timing-function:cubic-bezier(0.215,.61,.355,1)}from{opacity:0;-webkit-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes bounceInUp{100%,60%,75%,90%,from{-webkit-animation-timing-function:cubic-bezier(0.215,.61,.355,1);animation-timing-function:cubic-bezier(0.215,.61,.355,1)}from{opacity:0;-webkit-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.bounceInUp{-webkit-animation-name:bounceInUp;animation-name:bounceInUp}@-webkit-keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}100%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}@keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}100%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}.bounceOut{-webkit-animation-name:bounceOut;animation-name:bounceOut}@-webkit-keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}100%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}100%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.bounceOutDown{-webkit-animation-name:bounceOutDown;animation-name:bounceOutDown}@-webkit-keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}100%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}100%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.bounceOutLeft{-webkit-animation-name:bounceOutLeft;animation-name:bounceOutLeft}@-webkit-keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}100%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}100%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.bounceOutRight{-webkit-animation-name:bounceOutRight;animation-name:bounceOutRight}@-webkit-keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}100%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}100%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.bounceOutUp{-webkit-animation-name:bounceOutUp;animation-name:bounceOutUp}@-webkit-keyframes fadeIn{from{opacity:0}100%{opacity:1}}@keyframes fadeIn{from{opacity:0}100%{opacity:1}}.fadeIn{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes fadeInDown{from{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDown{from{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInDown{-webkit-animation-name:fadeInDown;animation-name:fadeInDown}@-webkit-keyframes fadeInDownBig{from{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDownBig{from{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInDownBig{-webkit-animation-name:fadeInDownBig;animation-name:fadeInDownBig}@-webkit-keyframes fadeInLeft{from{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeft{from{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInLeft{-webkit-animation-name:fadeInLeft;animation-name:fadeInLeft}@-webkit-keyframes fadeInLeftBig{from{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeftBig{from{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInLeftBig{-webkit-animation-name:fadeInLeftBig;animation-name:fadeInLeftBig}@-webkit-keyframes fadeInRight{from{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRight{from{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInRight{-webkit-animation-name:fadeInRight;animation-name:fadeInRight}@-webkit-keyframes fadeInRightBig{from{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRightBig{from{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInRightBig{-webkit-animation-name:fadeInRightBig;animation-name:fadeInRightBig}@-webkit-keyframes fadeInUp{from{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUp{from{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInUp{-webkit-animation-name:fadeInUp;animation-name:fadeInUp}@-webkit-keyframes fadeInUpBig{from{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUpBig{from{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInUpBig{-webkit-animation-name:fadeInUpBig;animation-name:fadeInUpBig}@-webkit-keyframes fadeOut{from{opacity:1}100%{opacity:0}}@keyframes fadeOut{from{opacity:1}100%{opacity:0}}.fadeOut{-webkit-animation-name:fadeOut;animation-name:fadeOut}@-webkit-keyframes fadeOutDown{from{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes fadeOutDown{from{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.fadeOutDown{-webkit-animation-name:fadeOutDown;animation-name:fadeOutDown}@-webkit-keyframes fadeOutDownBig{from{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes fadeOutDownBig{from{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.fadeOutDownBig{-webkit-animation-name:fadeOutDownBig;animation-name:fadeOutDownBig}@-webkit-keyframes fadeOutLeft{from{opacity:1}100%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}@keyframes fadeOutLeft{from{opacity:1}100%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.fadeOutLeft{-webkit-animation-name:fadeOutLeft;animation-name:fadeOutLeft}@-webkit-keyframes fadeOutLeftBig{from{opacity:1}100%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes fadeOutLeftBig{from{opacity:1}100%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.fadeOutLeftBig{-webkit-animation-name:fadeOutLeftBig;animation-name:fadeOutLeftBig}@-webkit-keyframes fadeOutRight{from{opacity:1}100%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}@keyframes fadeOutRight{from{opacity:1}100%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.fadeOutRight{-webkit-animation-name:fadeOutRight;animation-name:fadeOutRight}@-webkit-keyframes fadeOutRightBig{from{opacity:1}100%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes fadeOutRightBig{from{opacity:1}100%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.fadeOutRightBig{-webkit-animation-name:fadeOutRightBig;animation-name:fadeOutRightBig}@-webkit-keyframes fadeOutUp{from{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}@keyframes fadeOutUp{from{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}.fadeOutUp{-webkit-animation-name:fadeOutUp;animation-name:fadeOutUp}@-webkit-keyframes fadeOutUpBig{from{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes fadeOutUpBig{from{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.fadeOutUpBig{-webkit-animation-name:fadeOutUpBig;animation-name:fadeOutUpBig}@-webkit-keyframes flip{from{-webkit-transform:perspective(400px) rotate3d(0,1,0,-360deg);transform:perspective(400px) rotate3d(0,1,0,-360deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}50%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}100%{-webkit-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}@keyframes flip{from{-webkit-transform:perspective(400px) rotate3d(0,1,0,-360deg);transform:perspective(400px) rotate3d(0,1,0,-360deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}50%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}100%{-webkit-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}.animated.flip{-webkit-backface-visibility:visible;backface-visibility:visible;-webkit-animation-name:flip;animation-name:flip}@-webkit-keyframes flipInX{from{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(1,0,0,10deg);transform:perspective(400px) rotate3d(1,0,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-5deg);transform:perspective(400px) rotate3d(1,0,0,-5deg)}100%{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInX{from{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(1,0,0,10deg);transform:perspective(400px) rotate3d(1,0,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-5deg);transform:perspective(400px) rotate3d(1,0,0,-5deg)}100%{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInX{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInX;animation-name:flipInX}@-webkit-keyframes flipInY{from{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-20deg);transform:perspective(400px) rotate3d(0,1,0,-20deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(0,1,0,10deg);transform:perspective(400px) rotate3d(0,1,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-5deg);transform:perspective(400px) rotate3d(0,1,0,-5deg)}100%{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInY{from{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-20deg);transform:perspective(400px) rotate3d(0,1,0,-20deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(0,1,0,10deg);transform:perspective(400px) rotate3d(0,1,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-5deg);transform:perspective(400px) rotate3d(0,1,0,-5deg)}100%{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInY{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInY;animation-name:flipInY}@-webkit-keyframes flipOutX{from{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);opacity:1}100%{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);opacity:0}}@keyframes flipOutX{from{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);opacity:1}100%{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);opacity:0}}.flipOutX{-webkit-animation-name:flipOutX;animation-name:flipOutX;-webkit-backface-visibility:visible!important;backface-visibility:visible!important}@-webkit-keyframes flipOutY{from{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-15deg);transform:perspective(400px) rotate3d(0,1,0,-15deg);opacity:1}100%{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);opacity:0}}@keyframes flipOutY{from{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-15deg);transform:perspective(400px) rotate3d(0,1,0,-15deg);opacity:1}100%{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);opacity:0}}.flipOutY{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipOutY;animation-name:flipOutY}@-webkit-keyframes lightSpeedIn{from{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);transform:skewX(20deg);opacity:1}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg);opacity:1}100%{-webkit-transform:none;transform:none;opacity:1}}@keyframes lightSpeedIn{from{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);transform:skewX(20deg);opacity:1}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg);opacity:1}100%{-webkit-transform:none;transform:none;opacity:1}}.lightSpeedIn{-webkit-animation-name:lightSpeedIn;animation-name:lightSpeedIn;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}@-webkit-keyframes lightSpeedOut{from{opacity:1}100%{-webkit-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}@keyframes lightSpeedOut{from{opacity:1}100%{-webkit-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}.lightSpeedOut{-webkit-animation-name:lightSpeedOut;animation-name:lightSpeedOut;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}@-webkit-keyframes rotateIn{from{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,-200deg);transform:rotate3d(0,0,1,-200deg);opacity:0}100%{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateIn{from{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,-200deg);transform:rotate3d(0,0,1,-200deg);opacity:0}100%{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:none;transform:none;opacity:1}}.rotateIn{-webkit-animation-name:rotateIn;animation-name:rotateIn}@-webkit-keyframes rotateInDownLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInDownLeft{-webkit-animation-name:rotateInDownLeft;animation-name:rotateInDownLeft}@-webkit-keyframes rotateInDownRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInDownRight{-webkit-animation-name:rotateInDownRight;animation-name:rotateInDownRight}@-webkit-keyframes rotateInUpLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInUpLeft{-webkit-animation-name:rotateInUpLeft;animation-name:rotateInUpLeft}@-webkit-keyframes rotateInUpRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-90deg);transform:rotate3d(0,0,1,-90deg);opacity:0}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-90deg);transform:rotate3d(0,0,1,-90deg);opacity:0}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInUpRight{-webkit-animation-name:rotateInUpRight;animation-name:rotateInUpRight}@-webkit-keyframes rotateOut{from{-webkit-transform-origin:center;transform-origin:center;opacity:1}100%{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,200deg);transform:rotate3d(0,0,1,200deg);opacity:0}}@keyframes rotateOut{from{-webkit-transform-origin:center;transform-origin:center;opacity:1}100%{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,200deg);transform:rotate3d(0,0,1,200deg);opacity:0}}.rotateOut{-webkit-animation-name:rotateOut;animation-name:rotateOut}@-webkit-keyframes rotateOutDownLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}}@keyframes rotateOutDownLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}}.rotateOutDownLeft{-webkit-animation-name:rotateOutDownLeft;animation-name:rotateOutDownLeft}@-webkit-keyframes rotateOutDownRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}@keyframes rotateOutDownRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}.rotateOutDownRight{-webkit-animation-name:rotateOutDownRight;animation-name:rotateOutDownRight}@-webkit-keyframes rotateOutUpLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}@keyframes rotateOutUpLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}.rotateOutUpLeft{-webkit-animation-name:rotateOutUpLeft;animation-name:rotateOutUpLeft}@-webkit-keyframes rotateOutUpRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,90deg);transform:rotate3d(0,0,1,90deg);opacity:0}}@keyframes rotateOutUpRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,90deg);transform:rotate3d(0,0,1,90deg);opacity:0}}.rotateOutUpRight{-webkit-animation-name:rotateOutUpRight;animation-name:rotateOutUpRight}@-webkit-keyframes hinge{0%{-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate3d(0,0,1,80deg);transform:rotate3d(0,0,1,80deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}40%,80%{-webkit-transform:rotate3d(0,0,1,60deg);transform:rotate3d(0,0,1,60deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}100%{-webkit-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}@keyframes hinge{0%{-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate3d(0,0,1,80deg);transform:rotate3d(0,0,1,80deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}40%,80%{-webkit-transform:rotate3d(0,0,1,60deg);transform:rotate3d(0,0,1,60deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}100%{-webkit-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}.hinge{-webkit-animation-name:hinge;animation-name:hinge}@-webkit-keyframes rollIn{from{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg);transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes rollIn{from{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg);transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg)}100%{opacity:1;-webkit-transform:none;transform:none}}.rollIn{-webkit-animation-name:rollIn;animation-name:rollIn}@-webkit-keyframes rollOut{from{opacity:1}100%{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg);transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg)}}@keyframes rollOut{from{opacity:1}100%{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg);transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg)}}.rollOut{-webkit-animation-name:rollOut;animation-name:rollOut}@-webkit-keyframes zoomIn{from{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes zoomIn{from{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}.zoomIn{-webkit-animation-name:zoomIn;animation-name:zoomIn}@-webkit-keyframes zoomInDown{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}@keyframes zoomInDown{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}.zoomInDown{-webkit-animation-name:zoomInDown;animation-name:zoomInDown}@-webkit-keyframes zoomInLeft{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}@keyframes zoomInLeft{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}.zoomInLeft{-webkit-animation-name:zoomInLeft;animation-name:zoomInLeft}@-webkit-keyframes zoomInRight{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}@keyframes zoomInRight{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}.zoomInRight{-webkit-animation-name:zoomInRight;animation-name:zoomInRight}@-webkit-keyframes zoomInUp{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}@keyframes zoomInUp{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}.zoomInUp{-webkit-animation-name:zoomInUp;animation-name:zoomInUp}@-webkit-keyframes zoomOut{from{opacity:1}50%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}100%{opacity:0}}@keyframes zoomOut{from{opacity:1}50%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}100%{opacity:0}}.zoomOut{-webkit-animation-name:zoomOut;animation-name:zoomOut}@-webkit-keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}100%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}@keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}100%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}.zoomOutDown{-webkit-animation-name:zoomOutDown;animation-name:zoomOutDown}@-webkit-keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}100%{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;transform-origin:left center}}@keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}100%{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;transform-origin:left center}}.zoomOutLeft{-webkit-animation-name:zoomOutLeft;animation-name:zoomOutLeft}@-webkit-keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}100%{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;transform-origin:right center}}@keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}100%{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;transform-origin:right center}}.zoomOutRight{-webkit-animation-name:zoomOutRight;animation-name:zoomOutRight}@-webkit-keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}100%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}@keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}100%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}.zoomOutUp{-webkit-animation-name:zoomOutUp;animation-name:zoomOutUp}@-webkit-keyframes slideInDown{from{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:visible}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes slideInDown{from{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:visible}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.slideInDown{-webkit-animation-name:slideInDown;animation-name:slideInDown}@-webkit-keyframes slideInLeft{from{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:visible}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes slideInLeft{from{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:visible}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.slideInLeft{-webkit-animation-name:slideInLeft;animation-name:slideInLeft}@-webkit-keyframes slideInRight{from{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:visible}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes slideInRight{from{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:visible}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.slideInRight{-webkit-animation-name:slideInRight;animation-name:slideInRight}@-webkit-keyframes slideInUp{from{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes slideInUp{from{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.slideInUp{-webkit-animation-name:slideInUp;animation-name:slideInUp}@-webkit-keyframes slideOutDown{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}100%{visibility:hidden;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes slideOutDown{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}100%{visibility:hidden;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.slideOutDown{-webkit-animation-name:slideOutDown;animation-name:slideOutDown}@-webkit-keyframes slideOutLeft{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}100%{visibility:hidden;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}@keyframes slideOutLeft{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}100%{visibility:hidden;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.slideOutLeft{-webkit-animation-name:slideOutLeft;animation-name:slideOutLeft}@-webkit-keyframes slideOutRight{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}100%{visibility:hidden;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}@keyframes slideOutRight{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}100%{visibility:hidden;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.slideOutRight{-webkit-animation-name:slideOutRight;animation-name:slideOutRight}@-webkit-keyframes slideOutUp{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}100%{visibility:hidden;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}@keyframes slideOutUp{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}100%{visibility:hidden;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}.slideOutUp{-webkit-animation-name:slideOutUp;animation-name:slideOutUp} \ No newline at end of file diff --git a/frontend/assets/css/dashboard.css b/frontend/assets/css/dashboard.css deleted file mode 100644 index 93715f56..00000000 --- a/frontend/assets/css/dashboard.css +++ /dev/null @@ -1,2781 +0,0 @@ -/* light colors */ -@keyframes spin { - from { - transform: rotate(0deg); } - to { - transform: rotate(360deg); } } -@-webkit-keyframes spin { - from { - -webkit-transform: rotate(0deg); } - to { - -webkit-transform: rotate(360deg); } } -@-moz-keyframes spin { - from { - -moz-transform: rotate(0deg); } - to { - -moz-transform: rotate(360deg); } } -@-ms-keyframes spin { - from { - -ms-transform: rotate(0deg); } - to { - -ms-transform: rotate(360deg); } } -/* Font Smoothing */ -body, -h1, .h1, -h2, .h2, -h3, .h3, -h4, .h4, -h5, .h5, -h6, .h6, -p, -.navbar, -.brand, -.btn-simple, -.alert, -a, -.td-name, -td, -button.close { - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - font-family: "Roboto","Helvetica Neue",Arial,sans-serif; - font-weight: 400; } - -h1, .h1, h2, .h2, h3, .h3, h4, .h4 { - font-weight: 300; - margin: 30px 0 15px; } - -h1, .h1 { - font-size: 52px; } - -h2, .h2 { - font-size: 36px; } - -h3, .h3 { - font-size: 28px; - margin: 20px 0 10px; } - -h4, .h4 { - font-size: 22px; - line-height: 30px; } - -h5, .h5 { - font-size: 16px; - margin-bottom: 15px; } - -h6, .h6 { - font-size: 14px; - font-weight: 600; - text-transform: uppercase; } - -p { - font-size: 16px; - line-height: 1.5; } - -h1 small, h2 small, h3 small, h4 small, h5 small, h6 small, .h1 small, .h2 small, .h3 small, .h4 small, .h5 small, .h6 small, h1 .small, h2 .small, h3 .small, h4 .small, h5 .small, h6 .small, .h1 .small, .h2 .small, .h3 .small, .h4 .small, .h5 .small, .h6 .small { - color: #9A9A9A; - font-weight: 300; - line-height: 1.5; } - -h1 small, h2 small, h3 small, h1 .small, h2 .small, h3 .small { - font-size: 60%; } - -h1 .subtitle { - display: block; - margin: 0 0 30px; } - -.text-muted { - color: #9A9A9A; } - -.text-primary, .text-primary:hover { - color: #1D62F0 !important; } - -.text-info, .text-info:hover { - color: #1DC7EA !important; } - -.text-success, .text-success:hover { - color: #87CB16 !important; } - -.text-warning, .text-warning:hover { - color: #FF9500 !important; } - -.text-danger, .text-danger:hover { - color: #FF4A55 !important; } - -/* General overwrite */ -body, -.wrapper { - min-height: 100vh; - position: relative; - background: rgba(203, 203, 210, 0.15); - } - -a { - color: #56cdad; } - a:hover, a:focus { - color: #42d0ed; - text-decoration: none; } - -a:focus, a:active, -button::-moz-focus-inner, -input::-moz-focus-inner, -input[type="reset"]::-moz-focus-inner, -input[type="button"]::-moz-focus-inner, -input[type="submit"]::-moz-focus-inner, -select::-moz-focus-inner, -input[type="file"] > input[type="button"]::-moz-focus-inner { - outline: 0; } - -.ui-slider-handle:focus, -.navbar-toggle, -input:focus { - outline: 0 !important; } - -/* Animations */ -.form-control, -.input-group-addon, -.tagsinput, -.navbar, -.navbar .alert { - -webkit-transition: all 300ms linear; - -moz-transition: all 300ms linear; - -o-transition: all 300ms linear; - -ms-transition: all 300ms linear; - transition: all 300ms linear; } - -.sidebar .nav a, -.table > tbody > tr .td-actions .btn { - -webkit-transition: all 150ms ease-in; - -moz-transition: all 150ms ease-in; - -o-transition: all 150ms ease-in; - -ms-transition: all 150ms ease-in; - transition: all 150ms ease-in; } - -.btn { - -webkit-transition: all 100ms ease-in; - -moz-transition: all 100ms ease-in; - -o-transition: all 100ms ease-in; - -ms-transition: all 100ms ease-in; - transition: all 100ms ease-in; } - -.fa { - width: 18px; - text-align: center; } - -.margin-top { - margin-top: 50px; } - -.wrapper { - position: relative; - top: 0; - height: 100vh; } - -.sidebar { - position: absolute; - top: 0; - bottom: 0; - left: 0; - width: 260px; - display: block; - z-index: 1; - color: #fff; - font-weight: 200; - background-size: cover; - background-position: center center; } - .sidebar .sidebar-wrapper { - position: relative; - max-height: none; - min-height: 100%; - overflow: hidden; - width: 260px; - z-index: 4; } - .sidebar .sidebar-background { - position: absolute; - z-index: 1; - height: 100%; - width: 100%; - display: block; - top: 0; - left: 0; - background-size: cover; - background-position: center center; } - .sidebar .logo { - padding: 10px 15px; - border-bottom: 1px solid rgba(255, 255, 255, 0.2); } - .sidebar .logo p { - float: left; - font-size: 20px; - margin: 10px 10px; - color: #FFFFFF; - line-height: 20px; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; } - .sidebar .logo .simple-text { - text-transform: uppercase; - padding: 5px 0px; - display: block; - font-size: 18px; - color: #FFFFFF; - text-align: center; - font-weight: 400; - line-height: 30px; } - .sidebar .logo-tim { - border-radius: 50%; - border: 1px solid #333; - display: block; - height: 61px; - width: 61px; - float: left; - overflow: hidden; } - .sidebar .logo-tim img { - width: 60px; - height: 60px; } - .sidebar .nav { - margin-top: 20px; } - .sidebar .nav li > a { - color: #FFFFFF; - margin: 5px 15px; - opacity: .86; - border-radius: 4px; } - .sidebar .nav li:hover > a { - background: rgba(255, 255, 255, 0.13); - opacity: 1; } - .sidebar .nav li.active > a { - color: #FFFFFF; - opacity: 1; - background: rgba(255, 255, 255, 0.23); } - .sidebar .nav p { - margin: 0; - line-height: 30px; - font-size: 12px; - font-weight: 600; - text-transform: uppercase; } - .sidebar .nav i { - font-size: 28px; - float: left; - margin-right: 15px; - line-height: 30px; - width: 30px; - text-align: center; } - -.sidebar .logo, -body > .navbar-collapse .logo { - padding: 10px 15px; - border-bottom: 1px solid rgba(255, 255, 255, 0.2); } - .sidebar .logo p, - body > .navbar-collapse .logo p { - float: left; - font-size: 20px; - margin: 10px 10px; - color: #FFFFFF; - line-height: 20px; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; } - .sidebar .logo .simple-text, - body > .navbar-collapse .logo .simple-text { - text-transform: uppercase; - padding: 5px 0px; - display: block; - font-size: 18px; - color: #FFFFFF; - text-align: center; - font-weight: 400; - line-height: 30px; } -.sidebar .logo-tim, -body > .navbar-collapse .logo-tim { - border-radius: 50%; - border: 1px solid #333; - display: block; - height: 61px; - width: 61px; - float: left; - overflow: hidden; } - .sidebar .logo-tim img, - body > .navbar-collapse .logo-tim img { - width: 60px; - height: 60px; } -.sidebar:after, .sidebar:before, -body > .navbar-collapse:after, -body > .navbar-collapse:before { - display: block; - content: ""; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - z-index: 2; } -.sidebar:before, -body > .navbar-collapse:before { - opacity: .33; - background: #000000; } -.sidebar:after, -body > .navbar-collapse:after { - background: #787878; - background: -moz-linear-gradient(top, #787878 0%, #343434 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #787878), color-stop(100%, #343434)); - background: -webkit-linear-gradient(top, #787878 0%, #343434 100%); - background: -o-linear-gradient(top, #787878 0%, #343434 100%); - background: -ms-linear-gradient(top, #787878 0%, #343434 100%); - background: linear-gradient(to bottom, #787878 0%, #343434 100%); - background-size: 150% 150%; - z-index: 3; - opacity: 1; } -.sidebar[data-image]:after, .sidebar.has-image:after, -body > .navbar-collapse[data-image]:after, -body > .navbar-collapse.has-image:after { - opacity: .77; } -.sidebar[data-color="blue"]:after, -body > .navbar-collapse[data-color="blue"]:after { - background: #1F77D0; - background: -moz-linear-gradient(top, #1F77D0 0%, #533ce1 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #1F77D0), color-stop(100%, #533ce1)); - background: -webkit-linear-gradient(top, #1F77D0 0%, #533ce1 100%); - background: -o-linear-gradient(top, #1F77D0 0%, #533ce1 100%); - background: -ms-linear-gradient(top, #1F77D0 0%, #533ce1 100%); - background: linear-gradient(to bottom, #1F77D0 0%, #533ce1 100%); - background-size: 150% 150%; } -.sidebar[data-color="azure"]:after, -body > .navbar-collapse[data-color="azure"]:after { - background: #1DC7EA; - background: -moz-linear-gradient(top, #1DC7EA 0%, #4091ff 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #1DC7EA), color-stop(100%, #4091ff)); - background: -webkit-linear-gradient(top, #1DC7EA 0%, #4091ff 100%); - background: -o-linear-gradient(top, #1DC7EA 0%, #4091ff 100%); - background: -ms-linear-gradient(top, #1DC7EA 0%, #4091ff 100%); - background: linear-gradient(to bottom, #1DC7EA 0%, #4091ff 100%); - background-size: 150% 150%; } -.sidebar[data-color="green"]:after, -body > .navbar-collapse[data-color="green"]:after { - background: #449b82; - background: -moz-linear-gradient(top, #449b82 0%, #6dc030 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #449b82), color-stop(100%, #6dc030)); - background: -webkit-linear-gradient(top, #449b82 0%, #6dc030 100%); - background: -o-linear-gradient(top, #449b82 0%, #6dc030 100%); - background: -ms-linear-gradient(top, #449b82 0%, #6dc030 100%); - background: linear-gradient(to bottom, #449b82 0%, #6dc030 100%); - background-size: 150% 150%; } -.sidebar[data-color="nomad-green"]:after, -body > .navbar-collapse[data-color="nomad-green"]:after { - background: #449b82; - background: -moz-linear-gradient(top, #449b82 0%, #739873 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #449b82), color-stop(100%, #739873)); - background: -webkit-linear-gradient(top, #449b82 0%, #739873 100%); - background: -o-linear-gradient(top, #449b82 0%, #739873 100%); - background: -ms-linear-gradient(top, #449b82 0%, #739873 100%); - background: linear-gradient(to bottom, #449b82 0%, #739873 100%); - background-size: 150% 150%; } -.sidebar[data-color="orange"]:after, -body > .navbar-collapse[data-color="orange"]:after { - background: #FFA534; - background: -moz-linear-gradient(top, #FFA534 0%, #ff5221 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #FFA534), color-stop(100%, #ff5221)); - background: -webkit-linear-gradient(top, #FFA534 0%, #ff5221 100%); - background: -o-linear-gradient(top, #FFA534 0%, #ff5221 100%); - background: -ms-linear-gradient(top, #FFA534 0%, #ff5221 100%); - background: linear-gradient(to bottom, #FFA534 0%, #ff5221 100%); - background-size: 150% 150%; } -.sidebar[data-color="red"]:after, -body > .navbar-collapse[data-color="red"]:after { - background: #FB404B; - background: -moz-linear-gradient(top, #FB404B 0%, #bb0502 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #FB404B), color-stop(100%, #bb0502)); - background: -webkit-linear-gradient(top, #FB404B 0%, #bb0502 100%); - background: -o-linear-gradient(top, #FB404B 0%, #bb0502 100%); - background: -ms-linear-gradient(top, #FB404B 0%, #bb0502 100%); - background: linear-gradient(to bottom, #FB404B 0%, #bb0502 100%); - background-size: 150% 150%; } -.sidebar[data-color="purple"]:after, -body > .navbar-collapse[data-color="purple"]:after { - background: #9368E9; - background: -moz-linear-gradient(top, #9368E9 0%, #943bea 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #9368E9), color-stop(100%, #943bea)); - background: -webkit-linear-gradient(top, #9368E9 0%, #943bea 100%); - background: -o-linear-gradient(top, #9368E9 0%, #943bea 100%); - background: -ms-linear-gradient(top, #9368E9 0%, #943bea 100%); - background: linear-gradient(to bottom, #9368E9 0%, #943bea 100%); - background-size: 150% 150%; } - -.main-panel { - position: relative; - z-index: 2; - float: right; - width: calc(100% - 260px); - min-height: 100%; } - .main-panel > .content { - padding: 30px 15px; - min-height: calc(100% - 123px); } - .main-panel > .footer { - border-top: 1px solid #e7e7e7; } - .main-panel .navbar { - margin-bottom: 0; } - -.sidebar, -.main-panel { - overflow: auto; - max-height: 100%; - height: 100%; - -webkit-transition-property: top,bottom; - transition-property: top,bottom; - -webkit-transition-duration: .2s,.2s; - transition-duration: .2s,.2s; - -webkit-transition-timing-function: linear,linear; - transition-timing-function: linear,linear; - -webkit-overflow-scrolling: touch; } - -.btn { - border-width: 2px; - background-color: transparent; - font-weight: 400; - opacity: 0.8; - filter: alpha(opacity=80); - padding: 8px 16px; - border-color: #888888; - color: #888888; } - .btn:hover, .btn:focus, .btn:active, .btn.active, .open > .btn.dropdown-toggle { - background-color: transparent; - color: #777777; - border-color: #777777; } - .btn.disabled, .btn.disabled:hover, .btn.disabled:focus, .btn.disabled.focus, .btn.disabled:active, .btn.disabled.active, .btn:disabled, .btn:disabled:hover, .btn:disabled:focus, .btn:disabled.focus, .btn:disabled:active, .btn:disabled.active, .btn[disabled], .btn[disabled]:hover, .btn[disabled]:focus, .btn[disabled].focus, .btn[disabled]:active, .btn[disabled].active, fieldset[disabled] .btn, fieldset[disabled] .btn:hover, fieldset[disabled] .btn:focus, fieldset[disabled] .btn.focus, fieldset[disabled] .btn:active, fieldset[disabled] .btn.active { - background-color: transparent; - border-color: #888888; } - .btn.btn-fill { - color: #FFFFFF; - background-color: #888888; - opacity: 1; - filter: alpha(opacity=100); } - .btn.btn-fill:hover, .btn.btn-fill:focus, .btn.btn-fill:active, .btn.btn-fill.active, .open > .btn.btn-fill.dropdown-toggle { - background-color: #777777; - color: #FFFFFF; } - .btn.btn-fill .caret { - border-top-color: #FFFFFF; } - .btn .caret { - border-top-color: #888888; } - .btn:hover, .btn:focus { - opacity: 1; - filter: alpha(opacity=100); - outline: 0 !important; } - .btn:active, .btn.active, .open > .btn.dropdown-toggle { - -webkit-box-shadow: none; - box-shadow: none; - outline: 0 !important; } - .btn.btn-icon { - padding: 8px; } - -.btn-primary { - border-color: #3472F7; - color: #3472F7; } - .btn-primary:hover, .btn-primary:focus, .btn-primary:active, .btn-primary.active, .open > .btn-primary.dropdown-toggle { - background-color: transparent; - color: #1D62F0; - border-color: #1D62F0; } - .btn-primary.disabled, .btn-primary.disabled:hover, .btn-primary.disabled:focus, .btn-primary.disabled.focus, .btn-primary.disabled:active, .btn-primary.disabled.active, .btn-primary:disabled, .btn-primary:disabled:hover, .btn-primary:disabled:focus, .btn-primary:disabled.focus, .btn-primary:disabled:active, .btn-primary:disabled.active, .btn-primary[disabled], .btn-primary[disabled]:hover, .btn-primary[disabled]:focus, .btn-primary[disabled].focus, .btn-primary[disabled]:active, .btn-primary[disabled].active, fieldset[disabled] .btn-primary, fieldset[disabled] .btn-primary:hover, fieldset[disabled] .btn-primary:focus, fieldset[disabled] .btn-primary.focus, fieldset[disabled] .btn-primary:active, fieldset[disabled] .btn-primary.active { - background-color: transparent; - border-color: #3472F7; } - .btn-primary.btn-fill { - color: #FFFFFF; - background-color: #3472F7; - opacity: 1; - filter: alpha(opacity=100); } - .btn-primary.btn-fill:hover, .btn-primary.btn-fill:focus, .btn-primary.btn-fill:active, .btn-primary.btn-fill.active, .open > .btn-primary.btn-fill.dropdown-toggle { - background-color: #1D62F0; - color: #FFFFFF; } - .btn-primary.btn-fill .caret { - border-top-color: #FFFFFF; } - .btn-primary .caret { - border-top-color: #3472F7; } - -.btn-success { - border-color: #87CB16; - color: #87CB16; } - .btn-success:hover, .btn-success:focus, .btn-success:active, .btn-success.active, .open > .btn-success.dropdown-toggle { - background-color: transparent; - color: #049F0C; - border-color: #049F0C; } - .btn-success.disabled, .btn-success.disabled:hover, .btn-success.disabled:focus, .btn-success.disabled.focus, .btn-success.disabled:active, .btn-success.disabled.active, .btn-success:disabled, .btn-success:disabled:hover, .btn-success:disabled:focus, .btn-success:disabled.focus, .btn-success:disabled:active, .btn-success:disabled.active, .btn-success[disabled], .btn-success[disabled]:hover, .btn-success[disabled]:focus, .btn-success[disabled].focus, .btn-success[disabled]:active, .btn-success[disabled].active, fieldset[disabled] .btn-success, fieldset[disabled] .btn-success:hover, fieldset[disabled] .btn-success:focus, fieldset[disabled] .btn-success.focus, fieldset[disabled] .btn-success:active, fieldset[disabled] .btn-success.active { - background-color: transparent; - border-color: #87CB16; } - .btn-success.btn-fill { - color: #FFFFFF; - background-color: #87CB16; - opacity: 1; - filter: alpha(opacity=100); } - .btn-success.btn-fill:hover, .btn-success.btn-fill:focus, .btn-success.btn-fill:active, .btn-success.btn-fill.active, .open > .btn-success.btn-fill.dropdown-toggle { - background-color: #049F0C; - color: #FFFFFF; } - .btn-success.btn-fill .caret { - border-top-color: #FFFFFF; } - .btn-success .caret { - border-top-color: #87CB16; } - -.btn-info { - border-color: #1DC7EA; - color: #1DC7EA; } - .btn-info:hover, .btn-info:focus, .btn-info:active, .btn-info.active, .open > .btn-info.dropdown-toggle { - background-color: transparent; - color: #42d0ed; - border-color: #42d0ed; } - .btn-info.disabled, .btn-info.disabled:hover, .btn-info.disabled:focus, .btn-info.disabled.focus, .btn-info.disabled:active, .btn-info.disabled.active, .btn-info:disabled, .btn-info:disabled:hover, .btn-info:disabled:focus, .btn-info:disabled.focus, .btn-info:disabled:active, .btn-info:disabled.active, .btn-info[disabled], .btn-info[disabled]:hover, .btn-info[disabled]:focus, .btn-info[disabled].focus, .btn-info[disabled]:active, .btn-info[disabled].active, fieldset[disabled] .btn-info, fieldset[disabled] .btn-info:hover, fieldset[disabled] .btn-info:focus, fieldset[disabled] .btn-info.focus, fieldset[disabled] .btn-info:active, fieldset[disabled] .btn-info.active { - background-color: transparent; - border-color: #1DC7EA; } - .btn-info.btn-fill { - color: #FFFFFF; - background-color: #1DC7EA; - opacity: 1; - filter: alpha(opacity=100); } - .btn-info.btn-fill:hover, .btn-info.btn-fill:focus, .btn-info.btn-fill:active, .btn-info.btn-fill.active, .open > .btn-info.btn-fill.dropdown-toggle { - background-color: #42d0ed; - color: #FFFFFF; } - .btn-info.btn-fill .caret { - border-top-color: #FFFFFF; } - .btn-info .caret { - border-top-color: #1DC7EA; } - -.btn-warning { - border-color: #FF9500; - color: #FF9500; } - .btn-warning:hover, .btn-warning:focus, .btn-warning:active, .btn-warning.active, .open > .btn-warning.dropdown-toggle { - background-color: transparent; - color: #ED8D00; - border-color: #ED8D00; } - .btn-warning.disabled, .btn-warning.disabled:hover, .btn-warning.disabled:focus, .btn-warning.disabled.focus, .btn-warning.disabled:active, .btn-warning.disabled.active, .btn-warning:disabled, .btn-warning:disabled:hover, .btn-warning:disabled:focus, .btn-warning:disabled.focus, .btn-warning:disabled:active, .btn-warning:disabled.active, .btn-warning[disabled], .btn-warning[disabled]:hover, .btn-warning[disabled]:focus, .btn-warning[disabled].focus, .btn-warning[disabled]:active, .btn-warning[disabled].active, fieldset[disabled] .btn-warning, fieldset[disabled] .btn-warning:hover, fieldset[disabled] .btn-warning:focus, fieldset[disabled] .btn-warning.focus, fieldset[disabled] .btn-warning:active, fieldset[disabled] .btn-warning.active { - background-color: transparent; - border-color: #FF9500; } - .btn-warning.btn-fill { - color: #FFFFFF; - background-color: #FF9500; - opacity: 1; - filter: alpha(opacity=100); } - .btn-warning.btn-fill:hover, .btn-warning.btn-fill:focus, .btn-warning.btn-fill:active, .btn-warning.btn-fill.active, .open > .btn-warning.btn-fill.dropdown-toggle { - background-color: #ED8D00; - color: #FFFFFF; } - .btn-warning.btn-fill .caret { - border-top-color: #FFFFFF; } - .btn-warning .caret { - border-top-color: #FF9500; } - -.btn-danger { - border-color: #FF4A55; - color: #FF4A55; } - .btn-danger:hover, .btn-danger:focus, .btn-danger:active, .btn-danger.active, .open > .btn-danger.dropdown-toggle { - background-color: transparent; - color: #EE2D20; - border-color: #EE2D20; } - .btn-danger.disabled, .btn-danger.disabled:hover, .btn-danger.disabled:focus, .btn-danger.disabled.focus, .btn-danger.disabled:active, .btn-danger.disabled.active, .btn-danger:disabled, .btn-danger:disabled:hover, .btn-danger:disabled:focus, .btn-danger:disabled.focus, .btn-danger:disabled:active, .btn-danger:disabled.active, .btn-danger[disabled], .btn-danger[disabled]:hover, .btn-danger[disabled]:focus, .btn-danger[disabled].focus, .btn-danger[disabled]:active, .btn-danger[disabled].active, fieldset[disabled] .btn-danger, fieldset[disabled] .btn-danger:hover, fieldset[disabled] .btn-danger:focus, fieldset[disabled] .btn-danger.focus, fieldset[disabled] .btn-danger:active, fieldset[disabled] .btn-danger.active { - background-color: transparent; - border-color: #FF4A55; } - .btn-danger.btn-fill { - color: #FFFFFF; - background-color: #FF4A55; - opacity: 1; - filter: alpha(opacity=100); } - .btn-danger.btn-fill:hover, .btn-danger.btn-fill:focus, .btn-danger.btn-fill:active, .btn-danger.btn-fill.active, .open > .btn-danger.btn-fill.dropdown-toggle { - background-color: #EE2D20; - color: #FFFFFF; } - .btn-danger.btn-fill .caret { - border-top-color: #FFFFFF; } - .btn-danger .caret { - border-top-color: #FF4A55; } - -.btn-neutral { - border-color: #FFFFFF; - color: #FFFFFF; } - .btn-neutral:hover, .btn-neutral:focus, .btn-neutral:active, .btn-neutral.active, .open > .btn-neutral.dropdown-toggle { - background-color: transparent; - color: #FFFFFF; - border-color: #FFFFFF; } - .btn-neutral.disabled, .btn-neutral.disabled:hover, .btn-neutral.disabled:focus, .btn-neutral.disabled.focus, .btn-neutral.disabled:active, .btn-neutral.disabled.active, .btn-neutral:disabled, .btn-neutral:disabled:hover, .btn-neutral:disabled:focus, .btn-neutral:disabled.focus, .btn-neutral:disabled:active, .btn-neutral:disabled.active, .btn-neutral[disabled], .btn-neutral[disabled]:hover, .btn-neutral[disabled]:focus, .btn-neutral[disabled].focus, .btn-neutral[disabled]:active, .btn-neutral[disabled].active, fieldset[disabled] .btn-neutral, fieldset[disabled] .btn-neutral:hover, fieldset[disabled] .btn-neutral:focus, fieldset[disabled] .btn-neutral.focus, fieldset[disabled] .btn-neutral:active, fieldset[disabled] .btn-neutral.active { - background-color: transparent; - border-color: #FFFFFF; } - .btn-neutral.btn-fill { - color: #FFFFFF; - background-color: #FFFFFF; - opacity: 1; - filter: alpha(opacity=100); } - .btn-neutral.btn-fill:hover, .btn-neutral.btn-fill:focus, .btn-neutral.btn-fill:active, .btn-neutral.btn-fill.active, .open > .btn-neutral.btn-fill.dropdown-toggle { - background-color: #FFFFFF; - color: #FFFFFF; } - .btn-neutral.btn-fill .caret { - border-top-color: #FFFFFF; } - .btn-neutral .caret { - border-top-color: #FFFFFF; } - .btn-neutral:active, .btn-neutral.active, .open > .btn-neutral.dropdown-toggle { - background-color: #FFFFFF; - color: #888888; } - .btn-neutral.btn-fill, .btn-neutral.btn-fill:hover, .btn-neutral.btn-fill:focus { - color: #888888; } - .btn-neutral.btn-simple:active, .btn-neutral.btn-simple.active { - background-color: transparent; } - -.btn:disabled, .btn[disabled], .btn.disabled { - opacity: 0.5; - filter: alpha(opacity=50); } - -.btn-round { - border-width: 1px; - border-radius: 30px !important; - padding: 9px 18px; } - .btn-round.btn-icon { - padding: 9px; } - -.btn-simple { - border: 0; - font-size: 16px; - padding: 8px 16px; } - .btn-simple.btn-icon { - padding: 8px; } - -.btn-lg { - font-size: 18px; - border-radius: 6px; - padding: 14px 30px; - font-weight: 400; } - .btn-lg.btn-round { - padding: 15px 30px; } - .btn-lg.btn-simple { - padding: 16px 30px; } - -.btn-sm { - font-size: 12px; - border-radius: 3px; - padding: 5px 10px; } - .btn-sm.btn-round { - padding: 6px 10px; } - .btn-sm.btn-simple { - padding: 7px 10px; } - -.btn-xs { - font-size: 12px; - border-radius: 3px; - padding: 1px 5px; } - .btn-xs.btn-round { - padding: 2px 5px; } - .btn-xs.btn-simple { - padding: 3px 5px; } - -.btn-wd { - min-width: 140px; } - -.btn-group.select { - width: 100%; } - -.btn-group.select .btn { - text-align: left; } - -.btn-group.select .caret { - position: absolute; - top: 50%; - margin-top: -1px; - right: 8px; } - -.form-control::-moz-placeholder { - color: #DDDDDD; - opacity: 1; - filter: alpha(opacity=100); } - -.form-control:-moz-placeholder { - color: #DDDDDD; - opacity: 1; - filter: alpha(opacity=100); } - -.form-control::-webkit-input-placeholder { - color: #DDDDDD; - opacity: 1; - filter: alpha(opacity=100); } - -.form-control:-ms-input-placeholder { - color: #DDDDDD; - opacity: 1; - filter: alpha(opacity=100); } - -.form-control { - background-color: #FFFFFF; - border: 1px solid #E3E3E3; - border-radius: 4px; - color: #565656; - padding: 8px 12px; - height: 40px; - -webkit-box-shadow: none; - box-shadow: none; } - .form-control:focus { - background-color: #FFFFFF; - border: 1px solid #AAAAAA; - -webkit-box-shadow: none; - box-shadow: none; - outline: 0 !important; - color: #333333; } - .has-success .form-control, .has-error .form-control, .has-success .form-control:focus, .has-error .form-control:focus { - border-color: #E3E3E3; - -webkit-box-shadow: none; - box-shadow: none; } - .has-success .form-control { - color: #87CB16; } - .has-success .form-control:focus { - border-color: #87CB16; } - .has-error .form-control { - color: #FF4A55; } - .has-error .form-control:focus { - border-color: #FF4A55; } - .form-control + .form-control-feedback { - border-radius: 6px; - font-size: 14px; - margin-top: -7px; - position: absolute; - right: 10px; - top: 50%; - vertical-align: middle; } - .open .form-control { - border-radius: 4px 4px 0 0; - border-bottom-color: transparent; } - -.input-lg { - height: 55px; - padding: 14px 30px; } - -.has-error .form-control-feedback { - color: #FF4A55; } - -.has-success .form-control-feedback { - color: #87CB16; } - -.input-group-addon { - background-color: #FFFFFF; - border: 1px solid #E3E3E3; - border-radius: 4px; } - .has-success .input-group-addon, .has-error .input-group-addon { - background-color: #FFFFFF; - border: 1px solid #E3E3E3; } - .has-error .form-control:focus + .input-group-addon { - border-color: #FF4A55; - color: #FF4A55; } - .has-success .form-control:focus + .input-group-addon { - border-color: #87CB16; - color: #87CB16; } - .form-control:focus + .input-group-addon, .form-control:focus ~ .input-group-addon { - background-color: #FFFFFF; - border-color: #9A9A9A; } - -.input-group .form-control:first-child, -.input-group-addon:first-child, -.input-group-btn:first-child > .dropdown-toggle, -.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) { - border-right: 0 none; } - -.input-group .form-control:last-child, -.input-group-addon:last-child, -.input-group-btn:last-child > .dropdown-toggle, -.input-group-btn:first-child > .btn:not(:first-child) { - border-left: 0 none; } - -.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control { - background-color: #F5F5F5; - color: #888888; - cursor: not-allowed; } - -.input-group-btn .btn { - border-width: 1px; - padding: 9px 16px; } - -.input-group-btn .btn-default:not(.btn-fill) { - border-color: #DDDDDD; } - -.input-group-btn:last-child > .btn { - margin-left: 0; } - -.input-group-focus .input-group-addon { - border-color: #9A9A9A; } - -.alert { - border: 0; - border-radius: 0; - color: #FFFFFF; - padding: 10px 15px; - font-size: 14px; } - .container .alert { - border-radius: 4px; } - .navbar .alert { - border-radius: 0; - left: 0; - position: absolute; - right: 0; - top: 85px; - width: 100%; - z-index: 3; } - .navbar:not(.navbar-transparent) .alert { - top: 70px; } - .alert span[data-notify="icon"] { - font-size: 30px; - display: block; - left: 15px; - position: absolute; - top: 50%; - margin-top: -15px; } - .alert button.close { - position: absolute; - right: 10px; - top: 50%; - margin-top: -13px; - z-index: 1033; - background-color: #FFFFFF; - display: block; - border-radius: 50%; - opacity: .4; - line-height: 11px; - width: 25px; - height: 25px; - outline: 0 !important; - text-align: center; - padding: 3px; - font-weight: 300; } - .alert button.close:hover { - opacity: .55; } - .alert .close ~ span { - display: block; - max-width: 89%; } - .alert[data-notify="container"] { - padding: 10px 10px 10px 20px; - border-radius: 4px; } - .alert.alert-with-icon { - padding-left: 65px; } - -.alert-info { - background-color: #63d8f1; } - -.alert-success { - background-color: #5bb79d; } - -.alert-warning { - background-color: #ffbc67; } - -.alert-danger { - background-color: #fc727a; } - -.table .radio, -.table .checkbox { - position: relative; - height: 20px; - display: block; - width: 20px; - padding: 0px 0px; - margin: 0px 5px; - text-align: center; } - .table .radio .icons, - .table .checkbox .icons { - left: 5px; } -.table > thead > tr > th, -.table > tbody > tr > th, -.table > tfoot > tr > th, -.table > thead > tr > td, -.table > tbody > tr > td, -.table > tfoot > tr > td { - padding: 12px 8px; - vertical-align: middle; } -.table > thead > tr > th { - border-bottom-width: 1px; - font-size: 12px; - text-transform: uppercase; - color: #9A9A9A; - font-weight: 400; - padding-bottom: 5px; } -.table .td-actions .btn { - opacity: 0.36; - filter: alpha(opacity=36); } - .table .td-actions .btn.btn-xs { - padding-left: 3px; - padding-right: 3px; } -.table .td-actions { - min-width: 90px; } -.table > tbody > tr { - position: relative; } - .table > tbody > tr:hover .td-actions .btn { - opacity: 1; - filter: alpha(opacity=100); } - -/* Checkbox and radio */ -.checkbox, -.radio { - margin-bottom: 12px; - padding-left: 32px; - position: relative; - -webkit-transition: color 0.25s linear; - transition: color 0.25s linear; - font-size: 14px; - font-weight: normal; - line-height: 1.5; - color: #333333; } - -.checkbox input, -.radio input { - outline: none !important; - display: none; } - -.checkbox .icons, -.radio .icons { - color: #DDDDDD; - display: block; - height: 20px; - left: 0; - position: absolute; - top: 0; - width: 20px; - text-align: center; - line-height: 21px; - font-size: 20px; - cursor: pointer; - -webkit-transition: color 0.2s linear; - transition: color 0.2s linear; } - -.checkbox .icons .first-icon, -.radio .icons .first-icon, -.checkbox .icons .second-icon, -.radio .icons .second-icon { - display: inline-table; - position: absolute; - left: 0; - top: 0; - background-color: transparent; - margin: 0; - opacity: 1; - filter: alpha(opacity=100); } - -.checkbox .icons .second-icon, -.radio .icons .second-icon { - opacity: 0; - filter: alpha(opacity=0); } - -.checkbox:hover, -.radio:hover { - -webkit-transition: color 0.2s linear; - transition: color 0.2s linear; } - -.checkbox:hover .first-icon, -.radio:hover .first-icon { - opacity: 0; - filter: alpha(opacity=0); } - -.checkbox:hover .second-icon, -.radio:hover .second-icon { - opacity: 1; - filter: alpha(opacity=100); } - -.checkbox.checked, -.radio.checked { - color: #1DC7EA; } - -.checkbox.checked .first-icon, -.radio.checked .first-icon { - opacity: 0; - filter: alpha(opacity=0); } - -.checkbox.checked .second-icon, -.radio.checked .second-icon { - opacity: 1; - filter: alpha(opacity=100); - color: #1DC7EA; - -webkit-transition: color 0.2s linear; - transition: color 0.2s linear; } - -.checkbox.disabled, -.radio.disabled { - cursor: default; - color: #DDDDDD !important; } - -.checkbox.disabled .icons, -.radio.disabled .icons { - color: #DDDDDD !important; } - -.checkbox.disabled .first-icon, -.radio.disabled .first-icon { - opacity: 1; - filter: alpha(opacity=100); } - -.checkbox.disabled .second-icon, -.radio.disabled .second-icon { - opacity: 0; - filter: alpha(opacity=0); } - -.checkbox.disabled.checked .icons, -.radio.disabled.checked .icons { - color: #DDDDDD; } - -.checkbox.disabled.checked .first-icon, -.radio.disabled.checked .first-icon { - opacity: 0; - filter: alpha(opacity=0); } - -.checkbox.disabled.checked .second-icon, -.radio.disabled.checked .second-icon { - opacity: 1; - filter: alpha(opacity=100); - color: #D9D9D9; } - -/* ============================================================ - * bootstrapSwitch v1.3 by Larentis Mattia @spiritualGuru - * http://www.larentis.eu/switch/ - * ============================================================ - * Licensed under the Apache License, Version 2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * ============================================================ */ -.has-switch { - border-radius: 30px; - cursor: pointer; - display: inline-block; - line-height: 1.72222; - overflow: hidden; - position: relative; - text-align: left; - width: 60px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - -o-user-select: none; - user-select: none; - /* this code is for fixing safari bug with hidden overflow for border-radius */ - -webkit-mask: url("../img/mask.png") 0 0 no-repeat; - -webkit-mask-size: 60px 24px; - mask: url("../img/mask.png") 0 0 no-repeat; } - -.has-switch.deactivate { - opacity: 0.5; - filter: alpha(opacity=50); - cursor: default !important; } - -.has-switch.deactivate label, -.has-switch.deactivate span { - cursor: default !important; } - -.has-switch > div { - position: relative; - top: 0; - width: 100px; } - -.has-switch > div.switch-animate { - -webkit-transition: left 0.25s ease-out; - transition: left 0.25s ease-out; } - -.has-switch > div.switch-off { - left: -35px; } - -.has-switch > div.switch-on { - left: 0; } - -.has-switch > div label { - background-color: #FFFFFF; - background: white; - background: -moz-linear-gradient(top, white 0%, #f1f1f2 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #f1f1f2)); - background: -webkit-linear-gradient(top, white 0%, #f1f1f2 100%); - background: -o-linear-gradient(top, white 0%, #f1f1f2 100%); - background: -ms-linear-gradient(top, white 0%, #f1f1f2 100%); - background: linear-gradient(to bottom, white 0%, #f1f1f2 100%); - background-size: 150% 150%; - box-shadow: 0 1px 1px #FFFFFF inset, 0 1px 1px rgba(0, 0, 0, 0.25); - cursor: pointer; } - -.has-switch input[type=checkbox] { - display: none; } - -.has-switch span { - /* box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2) inset; */ - cursor: pointer; - float: left; - font-size: 11px; - font-weight: 400; - height: 24px; - line-height: 15px; - margin: 0; - padding-bottom: 6px; - padding-top: 5px; - position: relative; - text-align: center; - text-indent: -10px; - width: 50%; - z-index: 1; - -webkit-transition: 0.25s ease-out; - transition: 0.25s ease-out; } - -.has-switch span.switch-left { - background-color: #1DC7EA; - border-left: 1px solid transparent; - border-radius: 30px 0 0 30px; - color: #FFFFFF; } - -.has-switch .switch-off span.switch-left { - background-color: #DDDDDD; } - -.has-switch span.switch-right { - border-radius: 0 30px 30px 0; - background-color: #1DC7EA; - color: #ffffff; - text-indent: 1px; } - -.has-switch .switch-off span.switch-right { - background-color: #DDDDDD; } - -.has-switch label { - border-radius: 12px; - float: left; - height: 22px; - margin: 1px -13px; - padding: 0; - position: relative; - transition: all 0.25s ease-out 0s; - vertical-align: middle; - width: 22px; - z-index: 100; - -webkit-transition: 0.25s ease-out; - transition: 0.25s ease-out; } - -.has-switch .switch-on .fa-check:before { - margin-left: 10px; } - -.has-switch:hover .switch-on label { - margin: 1px -17px; - width: 26px; } - -.has-switch:hover .switch-off label { - margin: 1px -13px; - width: 26px; } - -.nav > li > a:hover, -.nav > li > a:focus { - background-color: transparent; } - -.navbar { - border: 0; - font-size: 16px; - border-radius: 0; } - .navbar .navbar-brand { - font-weight: 400; - margin: 5px 0px; - padding: 15px 15px; - font-size: 20px; } - .navbar .navbar-nav > li > a { - padding: 10px 15px; - margin: 10px 3px; - position: relative; } - .navbar .navbar-nav > li > a.btn { - margin: 15px 3px; - padding: 8px 16px; } - .navbar .navbar-nav > li > a.btn-round { - margin: 16px 3px; } - .navbar .navbar-nav > li > a [class^="fa"] { - font-size: 19px; - position: relative; - line-height: 16px; - top: 1px; } - .navbar .navbar-nav .notification { - position: absolute; - background-color: #FB404B; - text-align: center; - border-radius: 10px; - min-width: 18px; - padding: 0 5px; - height: 18px; - font-size: 12px; - color: #FFFFFF; - font-weight: bold; - line-height: 18px; - top: 0px; - left: 7px; } - .navbar .btn { - margin: 15px 3px; - font-size: 14px; } - .navbar .btn-simple { - font-size: 16px; } - .navbar.fixed { - width: calc(100% - $sidebar-width); - right: 0; - left: auto; - border-radius: 0; } - -.navbar-nav > li > .dropdown-menu { - border-radius: 10px; - margin-top: -5px; } - -.navbar-transparent .navbar-brand, [class*="navbar-ct"] .navbar-brand { - color: #FFFFFF; - opacity: 0.9; - filter: alpha(opacity=90); } - .navbar-transparent .navbar-brand:focus, .navbar-transparent .navbar-brand:hover, [class*="navbar-ct"] .navbar-brand:focus, [class*="navbar-ct"] .navbar-brand:hover { - background-color: transparent; - opacity: 1; - filter: alpha(opacity=100); } -.navbar-transparent .navbar-nav > li > a:not(.btn), [class*="navbar-ct"] .navbar-nav > li > a:not(.btn) { - color: #FFFFFF; - border-color: #FFFFFF; - opacity: 0.8; - filter: alpha(opacity=80); } -.navbar-transparent .navbar-nav > .active > a:not(.btn), -.navbar-transparent .navbar-nav > .active > a:hover:not(.btn), -.navbar-transparent .navbar-nav > .active > a:focus:not(.btn), -.navbar-transparent .navbar-nav > li > a:hover:not(.btn), -.navbar-transparent .navbar-nav > li > a:focus:not(.btn), [class*="navbar-ct"] .navbar-nav > .active > a:not(.btn), -[class*="navbar-ct"] .navbar-nav > .active > a:hover:not(.btn), -[class*="navbar-ct"] .navbar-nav > .active > a:focus:not(.btn), -[class*="navbar-ct"] .navbar-nav > li > a:hover:not(.btn), -[class*="navbar-ct"] .navbar-nav > li > a:focus:not(.btn) { - background-color: transparent; - border-radius: 3px; - color: #FFFFFF; - opacity: 1; - filter: alpha(opacity=100); } -.navbar-transparent .navbar-nav .nav > li > a.btn:hover, [class*="navbar-ct"] .navbar-nav .nav > li > a.btn:hover { - background-color: transparent; } -.navbar-transparent .navbar-nav > .dropdown > a .caret, -.navbar-transparent .navbar-nav > .dropdown > a:hover .caret, -.navbar-transparent .navbar-nav > .dropdown > a:focus .caret, [class*="navbar-ct"] .navbar-nav > .dropdown > a .caret, -[class*="navbar-ct"] .navbar-nav > .dropdown > a:hover .caret, -[class*="navbar-ct"] .navbar-nav > .dropdown > a:focus .caret { - border-bottom-color: #FFFFFF; - border-top-color: #FFFFFF; } -.navbar-transparent .navbar-nav > .open > a, -.navbar-transparent .navbar-nav > .open > a:hover, -.navbar-transparent .navbar-nav > .open > a:focus, [class*="navbar-ct"] .navbar-nav > .open > a, -[class*="navbar-ct"] .navbar-nav > .open > a:hover, -[class*="navbar-ct"] .navbar-nav > .open > a:focus { - background-color: transparent; - color: #FFFFFF; - opacity: 1; - filter: alpha(opacity=100); } -.navbar-transparent .btn-default, [class*="navbar-ct"] .btn-default { - color: #FFFFFF; - border-color: #FFFFFF; } -.navbar-transparent .btn-default.btn-fill, [class*="navbar-ct"] .btn-default.btn-fill { - color: #9A9A9A; - background-color: #FFFFFF; - opacity: 0.9; - filter: alpha(opacity=90); } -.navbar-transparent .btn-default.btn-fill:hover, -.navbar-transparent .btn-default.btn-fill:focus, -.navbar-transparent .btn-default.btn-fill:active, -.navbar-transparent .btn-default.btn-fill.active, -.navbar-transparent .open .dropdown-toggle.btn-fill.btn-default, [class*="navbar-ct"] .btn-default.btn-fill:hover, -[class*="navbar-ct"] .btn-default.btn-fill:focus, -[class*="navbar-ct"] .btn-default.btn-fill:active, -[class*="navbar-ct"] .btn-default.btn-fill.active, -[class*="navbar-ct"] .open .dropdown-toggle.btn-fill.btn-default { - border-color: #FFFFFF; - opacity: 1; - filter: alpha(opacity=100); } - -.navbar-transparent .dropdown-menu .divider { - background-color: rgba(255, 255, 255, 0.2); } - -.nav-open .nav .caret { - border-bottom-color: #FFFFFF; - border-top-color: #FFFFFF; } - -.navbar-default { - background-color: rgba(255, 255, 255, 0.96); - border-bottom: 1px solid rgba(0, 0, 0, 0.1); } - .navbar-default .navbar-nav > li > a:not(.btn) { - color: #9A9A9A; } - .navbar-default .navbar-nav > .active > a, - .navbar-default .navbar-nav > .active > a:not(.btn):hover, - .navbar-default .navbar-nav > .active > a:not(.btn):focus, - .navbar-default .navbar-nav > li > a:not(.btn):hover, - .navbar-default .navbar-nav > li > a:not(.btn):focus { - background-color: transparent; - border-radius: 3px; - color: #1DC7EA; - opacity: 1; - filter: alpha(opacity=100); } - .navbar-default .navbar-nav > .dropdown > a:hover .caret, - .navbar-default .navbar-nav > .dropdown > a:focus .caret { - border-bottom-color: #1DC7EA; - border-top-color: #1DC7EA; } - .navbar-default .navbar-nav > .open > a, - .navbar-default .navbar-nav > .open > a:hover, - .navbar-default .navbar-nav > .open > a:focus { - background-color: transparent; - color: #1DC7EA; } - .navbar-default .navbar-nav .navbar-toggle:hover, .navbar-default .navbar-nav .navbar-toggle:focus { - background-color: transparent; } - .navbar-default:not(.navbar-transparent) .btn-default:hover { - color: #1DC7EA; - border-color: #1DC7EA; } - .navbar-default:not(.navbar-transparent) .btn-neutral, .navbar-default:not(.navbar-transparent) .btn-neutral:hover, .navbar-default:not(.navbar-transparent) .btn-neutral:active { - color: #9A9A9A; } - -/* Navbar with icons */ -.navbar-icons.navbar .navbar-brand { - margin-top: 12px; - margin-bottom: 12px; } -.navbar-icons .navbar-nav > li > a { - text-align: center; - padding: 6px 15px; - margin: 6px 3px; } -.navbar-icons .navbar-nav [class^="pe"] { - font-size: 30px; - position: relative; } -.navbar-icons .navbar-nav p { - margin: 3px 0 0; } - -.navbar-form { - -webkit-box-shadow: none; - box-shadow: none; } - .navbar-form .form-control { - border-radius: 0; - border: 0; - padding: 0; - background-color: transparent; - height: 22px; - font-size: 16px; - line-height: 1.5; - color: #E3E3E3; } - .navbar-transparent .navbar-form .form-control, [class*="navbar-ct"] .navbar-form .form-control { - color: #FFFFFF; - border: 0; - border-bottom: 1px solid rgba(255, 255, 255, 0.6); } - -.navbar-ct-blue { - background-color: #4091e2; } - -.navbar-ct-azure { - background-color: #63d8f1; } - -.navbar-ct-green { - background-color: #5bb79d; } - -.navbar-ct-orange { - background-color: #ffbc67; } - -.navbar-ct-red { - background-color: #fc727a; } - -.navbar-transparent { - padding-top: 15px; - background-color: transparent; - border-bottom: 1px solid transparent; } - -.navbar-toggle { - margin-top: 19px; - margin-bottom: 19px; - border: 0; } - .navbar-toggle .icon-bar { - background-color: #FFFFFF; } - .navbar-toggle .navbar-collapse, - .navbar-toggle .navbar-form { - border-color: transparent; } - .navbar-toggle.navbar-default .navbar-toggle:hover, .navbar-toggle.navbar-default .navbar-toggle:focus { - background-color: transparent; } - -.footer { - background-color: #FFFFFF; - line-height: 20px; } - .footer nav > ul { - list-style: none; - margin: 0; - padding: 0; - font-weight: normal; } - .footer nav > ul a:not(.btn) { - color: #9A9A9A; - display: block; - margin-bottom: 3px; } - .footer nav > ul a:not(.btn):hover, .footer nav > ul a:not(.btn):focus { - color: #777777; } - .footer .social-area { - padding: 15px 0; } - .footer .social-area h5 { - padding-bottom: 15px; } - .footer .social-area > a:not(.btn) { - color: #9A9A9A; - display: inline-block; - vertical-align: top; - padding: 10px 5px; - font-size: 20px; - font-weight: normal; - line-height: 20px; - text-align: center; } - .footer .social-area > a:not(.btn):hover, .footer .social-area > a:not(.btn):focus { - color: #777777; } - .footer .copyright { - color: #777777; - padding: 10px 15px; - margin: 10px 3px; - line-height: 20px; - font-size: 14px; } - .footer hr { - border-color: #DDDDDD; } - .footer .title { - color: #777777; } - -.footer-default { - background-color: #F5F5F5; } - -.footer:not(.footer-big) nav > ul { - font-size: 14px; } - .footer:not(.footer-big) nav > ul li { - margin-left: 20px; - float: left; } - .footer:not(.footer-big) nav > ul a { - padding: 10px 0px; - margin: 10px 10px 10px 0px; } - -.dropdown-menu { - visibility: hidden; - margin: 0; - padding: 0; - border-radius: 10px; - display: block; - z-index: 9000; - position: absolute; - opacity: 0; - filter: alpha(opacity=0); - -webkit-box-shadow: 1px 2px 3px rgba(0, 0, 0, 0.125); - box-shadow: 1px 2px 3px rgba(0, 0, 0, 0.125); } - .open .dropdown-menu { - opacity: 1; - filter: alpha(opacity=100); - visibility: visible; } - .select .dropdown-menu { - border-radius: 0 0 10px 10px; - -webkit-box-shadow: none; - box-shadow: none; - -webkit-transform-origin: 50% -40px; - -moz-transform-origin: 50% -40px; - -o-transform-origin: 50% -40px; - -ms-transform-origin: 50% -40px; - transform-origin: 50% -40px; - -webkit-transform: scale(1); - -moz-transform: scale(1); - -o-transform: scale(1); - -ms-transform: scale(1); - transform: scale(1); - -webkit-transition: all 150ms linear; - -moz-transition: all 150ms linear; - -o-transition: all 150ms linear; - -ms-transition: all 150ms linear; - transition: all 150ms linear; - margin-top: -20px; } - .select.open .dropdown-menu { - margin-top: -1px; } - .dropdown-menu > li > a { - padding: 8px 16px; - color: #333333; } - .dropdown-menu > li > a img { - margin-top: -3px; } - .dropdown-menu > li > a:focus { - outline: 0 !important; } - .btn-group.select .dropdown-menu { - min-width: 100%; } - .dropdown-menu > li:first-child > a { - border-top-left-radius: 10px; - border-top-right-radius: 10px; } - .dropdown-menu > li:last-child > a { - border-bottom-left-radius: 10px; - border-bottom-right-radius: 10px; } - .select .dropdown-menu > li:first-child > a { - border-radius: 0; - border-bottom: 0 none; } - .dropdown-menu > li > a:hover, - .dropdown-menu > li > a:focus { - background-color: #F5F5F5; - color: #333333; - opacity: 1; - text-decoration: none; } - .dropdown-menu.dropdown-blue > li > a:hover, .dropdown-menu.dropdown-blue > li > a:focus { - background-color: rgba(52, 114, 247, 0.2); } - .dropdown-menu.dropdown-azure > li > a:hover, .dropdown-menu.dropdown-azure > li > a:focus { - background-color: rgba(29, 199, 234, 0.2); } - .dropdown-menu.ct-green > li > a:hover, .dropdown-menu.ct-green > li > a:focus { - background-color: rgba(135, 203, 22, 0.2); } - .dropdown-menu.dropdown-orange > li > a:hover, .dropdown-menu.dropdown-orange > li > a:focus { - background-color: rgba(255, 149, 0, 0.2); } - .dropdown-menu.dropdown-red > li > a:hover, .dropdown-menu.dropdown-red > li > a:focus { - background-color: rgba(255, 74, 85, 0.2); } - -.dropdown-with-icons > li > a { - padding-left: 0px; - line-height: 28px; } -.dropdown-with-icons i { - text-align: center; - line-height: 28px; - float: left; } - .dropdown-with-icons i[class^="pe-"] { - font-size: 24px; - width: 46px; } - .dropdown-with-icons i[class^="fa"] { - font-size: 14px; - width: 38px; } - -.btn-group.select { - overflow: hidden; } - -.btn-group.select.open { - overflow: visible; } - -.card { - border-radius: 4px; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 0 0 1px rgba(63, 63, 68, 0.1); - background-color: #FFFFFF; - margin-bottom: 30px; } - .card .image { - width: 100%; - overflow: hidden; - height: 260px; - border-radius: 4px 4px 0 0; - position: relative; - -webkit-transform-style: preserve-3d; - -moz-transform-style: preserve-3d; - transform-style: preserve-3d; } - .card .image img { - width: 100%; } - .card .filter { - position: absolute; - z-index: 2; - background-color: rgba(0, 0, 0, 0.68); - top: 0; - left: 0; - width: 100%; - height: 100%; - text-align: center; - opacity: 0; - filter: alpha(opacity=0); } - .card .filter .btn { - position: relative; - top: 50%; - -webkit-transform: translateY(-50%); - -ms-transform: translateY(-50%); - transform: translateY(-50%); } - .card:hover .filter { - opacity: 1; - filter: alpha(opacity=100); } - .card .btn-hover { - opacity: 0; - filter: alpha(opacity=0); } - .card:hover .btn-hover { - opacity: 1; - filter: alpha(opacity=100); } - .card .content { - padding: 15px 15px 10px 15px; } - .card .header { - padding: 15px 15px 0; } - .card .category, - .card label { - font-size: 14px; - font-weight: 400; - color: #9A9A9A; - margin-bottom: 0px; } - .card .category i, - .card label i { - font-size: 16px; } - .card label { - font-size: 12px; - margin-bottom: 5px; - text-transform: uppercase; } - .card .title { - margin: 0; - color: #333333; - font-weight: 300; } - .card .avatar { - width: 30px; - height: 30px; - overflow: hidden; - border-radius: 50%; - margin-right: 5px; } - .card .description { - font-size: 14px; - color: #333; } - .card .footer { - padding: 0; - background-color: transparent; - line-height: 30px; } - .card .footer .legend { - padding: 5px 0; } - .card .footer hr { - margin-top: 5px; - margin-bottom: 5px; } - .card .stats { - color: #a9a9a9; } - .card .footer div { - display: inline-block; } - .card .author { - font-size: 12px; - font-weight: 600; - text-transform: uppercase; } - .card .author i { - font-size: 14px; } - .card h6 { - font-size: 12px; - margin: 0; } - .card.card-separator:after { - height: 100%; - right: -15px; - top: 0; - width: 1px; - background-color: #DDDDDD; - content: ""; - position: absolute; } - .card .ct-chart { - margin: 30px 0 30px; - height: 245px; } - .card .table tbody td:first-child, - .card .table thead th:first-child { - padding-left: 15px; } - .card .table tbody td:last-child, - .card .table thead th:last-child { - padding-right: 15px; } - .card .alert { - border-radius: 4px; - position: relative; } - .card .alert.alert-with-icon { - padding-left: 65px; } - -.card-user .image { - height: 110px; } -.card-user .image-plain { - height: 0; - margin-top: 110px; } -.card-user .author { - text-align: center; - text-transform: none; - margin-top: -70px; } -.card-user .avatar { - width: 124px; - height: 124px; - border: 5px solid #FFFFFF; - position: relative; - margin-bottom: 15px; } - .card-user .avatar.border-gray { - border-color: #EEEEEE; } -.card-user .title { - line-height: 24px; } -.card-user .content { - min-height: 240px; } - -.card-user .footer, -.card-price .footer { - padding: 5px 15px 10px; } -.card-user hr, -.card-price hr { - margin: 5px 15px; } - -.card-plain { - background-color: transparent; - box-shadow: none; - border-radius: 0; } - .card-plain .image { - border-radius: 4px; } - -.ct-label { - fill: rgba(0, 0, 0, 0.4); - color: rgba(0, 0, 0, 0.4); - font-size: 1.3rem; - line-height: 1; } - -.ct-chart-line .ct-label, -.ct-chart-bar .ct-label { - display: block; - display: -webkit-box; - display: -moz-box; - display: -ms-flexbox; - display: -webkit-flex; - display: flex; } - -.ct-label.ct-horizontal.ct-start { - -webkit-box-align: flex-end; - -webkit-align-items: flex-end; - -ms-flex-align: flex-end; - align-items: flex-end; - -webkit-box-pack: flex-start; - -webkit-justify-content: flex-start; - -ms-flex-pack: flex-start; - justify-content: flex-start; - text-align: left; - text-anchor: start; } - -.ct-label.ct-horizontal.ct-end { - -webkit-box-align: flex-start; - -webkit-align-items: flex-start; - -ms-flex-align: flex-start; - align-items: flex-start; - -webkit-box-pack: flex-start; - -webkit-justify-content: flex-start; - -ms-flex-pack: flex-start; - justify-content: flex-start; - text-align: left; - text-anchor: start; } - -.ct-label.ct-vertical.ct-start { - -webkit-box-align: flex-end; - -webkit-align-items: flex-end; - -ms-flex-align: flex-end; - align-items: flex-end; - -webkit-box-pack: flex-end; - -webkit-justify-content: flex-end; - -ms-flex-pack: flex-end; - justify-content: flex-end; - text-align: right; - text-anchor: end; } - -.ct-label.ct-vertical.ct-end { - -webkit-box-align: flex-end; - -webkit-align-items: flex-end; - -ms-flex-align: flex-end; - align-items: flex-end; - -webkit-box-pack: flex-start; - -webkit-justify-content: flex-start; - -ms-flex-pack: flex-start; - justify-content: flex-start; - text-align: left; - text-anchor: start; } - -.ct-chart-bar .ct-label.ct-horizontal.ct-start { - -webkit-box-align: flex-end; - -webkit-align-items: flex-end; - -ms-flex-align: flex-end; - align-items: flex-end; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - text-align: center; - text-anchor: start; } - -.ct-chart-bar .ct-label.ct-horizontal.ct-end { - -webkit-box-align: flex-start; - -webkit-align-items: flex-start; - -ms-flex-align: flex-start; - align-items: flex-start; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - text-align: center; - text-anchor: start; } - -.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-start { - -webkit-box-align: flex-end; - -webkit-align-items: flex-end; - -ms-flex-align: flex-end; - align-items: flex-end; - -webkit-box-pack: flex-start; - -webkit-justify-content: flex-start; - -ms-flex-pack: flex-start; - justify-content: flex-start; - text-align: left; - text-anchor: start; } - -.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-end { - -webkit-box-align: flex-start; - -webkit-align-items: flex-start; - -ms-flex-align: flex-start; - align-items: flex-start; - -webkit-box-pack: flex-start; - -webkit-justify-content: flex-start; - -ms-flex-pack: flex-start; - justify-content: flex-start; - text-align: left; - text-anchor: start; } - -.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-start { - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-pack: flex-end; - -webkit-justify-content: flex-end; - -ms-flex-pack: flex-end; - justify-content: flex-end; - text-align: right; - text-anchor: end; } - -.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-end { - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-pack: flex-start; - -webkit-justify-content: flex-start; - -ms-flex-pack: flex-start; - justify-content: flex-start; - text-align: left; - text-anchor: end; } - -.ct-grid { - stroke: rgba(0, 0, 0, 0.2); - stroke-width: 1px; - stroke-dasharray: 2px; } - -.ct-point { - stroke-width: 8px; - stroke-linecap: round; } - -.ct-line { - fill: none; - stroke-width: 3px; } - -.ct-area { - stroke: none; - fill-opacity: 0.8; } - -.ct-bar { - fill: none; - stroke-width: 10px; } - -.ct-slice-donut { - fill: none; - stroke-width: 60px; } - -.ct-series-a .ct-point, .ct-series-a .ct-line, .ct-series-a .ct-bar, .ct-series-a .ct-slice-donut { - stroke: #1DC7EA; } -.ct-series-a .ct-slice-pie, .ct-series-a .ct-area { - fill: #1DC7EA; } - -.ct-series-b .ct-point, .ct-series-b .ct-line, .ct-series-b .ct-bar, .ct-series-b .ct-slice-donut { - stroke: #FB404B; } -.ct-series-b .ct-slice-pie, .ct-series-b .ct-area { - fill: #FB404B; } - -.ct-series-c .ct-point, .ct-series-c .ct-line, .ct-series-c .ct-bar, .ct-series-c .ct-slice-donut { - stroke: #FFA534; } -.ct-series-c .ct-slice-pie, .ct-series-c .ct-area { - fill: #FFA534; } - -.ct-series-d .ct-point, .ct-series-d .ct-line, .ct-series-d .ct-bar, .ct-series-d .ct-slice-donut { - stroke: #9368E9; } -.ct-series-d .ct-slice-pie, .ct-series-d .ct-area { - fill: #9368E9; } - -.ct-series-e .ct-point, .ct-series-e .ct-line, .ct-series-e .ct-bar, .ct-series-e .ct-slice-donut { - stroke: #449b82; } -.ct-series-e .ct-slice-pie, .ct-series-e .ct-area { - fill: #449b82; } - -.ct-series-f .ct-point, .ct-series-f .ct-line, .ct-series-f .ct-bar, .ct-series-f .ct-slice-donut { - stroke: #1F77D0; } -.ct-series-f .ct-slice-pie, .ct-series-f .ct-area { - fill: #1F77D0; } - -.ct-series-g .ct-point, .ct-series-g .ct-line, .ct-series-g .ct-bar, .ct-series-g .ct-slice-donut { - stroke: #5e5e5e; } -.ct-series-g .ct-slice-pie, .ct-series-g .ct-area { - fill: #5e5e5e; } - -.ct-series-h .ct-point, .ct-series-h .ct-line, .ct-series-h .ct-bar, .ct-series-h .ct-slice-donut { - stroke: #dd4b39; } -.ct-series-h .ct-slice-pie, .ct-series-h .ct-area { - fill: #dd4b39; } - -.ct-series-i .ct-point, .ct-series-i .ct-line, .ct-series-i .ct-bar, .ct-series-i .ct-slice-donut { - stroke: #35465c; } -.ct-series-i .ct-slice-pie, .ct-series-i .ct-area { - fill: #35465c; } - -.ct-series-j .ct-point, .ct-series-j .ct-line, .ct-series-j .ct-bar, .ct-series-j .ct-slice-donut { - stroke: #e52d27; } -.ct-series-j .ct-slice-pie, .ct-series-j .ct-area { - fill: #e52d27; } - -.ct-series-k .ct-point, .ct-series-k .ct-line, .ct-series-k .ct-bar, .ct-series-k .ct-slice-donut { - stroke: #55acee; } -.ct-series-k .ct-slice-pie, .ct-series-k .ct-area { - fill: #55acee; } - -.ct-series-l .ct-point, .ct-series-l .ct-line, .ct-series-l .ct-bar, .ct-series-l .ct-slice-donut { - stroke: #cc2127; } -.ct-series-l .ct-slice-pie, .ct-series-l .ct-area { - fill: #cc2127; } - -.ct-series-m .ct-point, .ct-series-m .ct-line, .ct-series-m .ct-bar, .ct-series-m .ct-slice-donut { - stroke: #1769ff; } -.ct-series-m .ct-slice-pie, .ct-series-m .ct-area { - fill: #1769ff; } - -.ct-series-n .ct-point, .ct-series-n .ct-line, .ct-series-n .ct-bar, .ct-series-n .ct-slice-donut { - stroke: #6188e2; } -.ct-series-n .ct-slice-pie, .ct-series-n .ct-area { - fill: #6188e2; } - -.ct-series-o .ct-point, .ct-series-o .ct-line, .ct-series-o .ct-bar, .ct-series-o .ct-slice-donut { - stroke: #a748ca; } -.ct-series-o .ct-slice-pie, .ct-series-o .ct-area { - fill: #a748ca; } - -.ct-square { - display: block; - position: relative; - width: 100%; } - .ct-square:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 100%; } - .ct-square:after { - content: ""; - display: table; - clear: both; } - .ct-square > svg { - display: block; - position: absolute; - top: 0; - left: 0; } - -.ct-minor-second { - display: block; - position: relative; - width: 100%; } - .ct-minor-second:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 93.75%; } - .ct-minor-second:after { - content: ""; - display: table; - clear: both; } - .ct-minor-second > svg { - display: block; - position: absolute; - top: 0; - left: 0; } - -.ct-major-second { - display: block; - position: relative; - width: 100%; } - .ct-major-second:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 88.88889%; } - .ct-major-second:after { - content: ""; - display: table; - clear: both; } - .ct-major-second > svg { - display: block; - position: absolute; - top: 0; - left: 0; } - -.ct-minor-third { - display: block; - position: relative; - width: 100%; } - .ct-minor-third:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 83.33333%; } - .ct-minor-third:after { - content: ""; - display: table; - clear: both; } - .ct-minor-third > svg { - display: block; - position: absolute; - top: 0; - left: 0; } - -.ct-major-third { - display: block; - position: relative; - width: 100%; } - .ct-major-third:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 80%; } - .ct-major-third:after { - content: ""; - display: table; - clear: both; } - .ct-major-third > svg { - display: block; - position: absolute; - top: 0; - left: 0; } - -.ct-perfect-fourth { - display: block; - position: relative; - width: 100%; } - .ct-perfect-fourth:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 75%; } - .ct-perfect-fourth:after { - content: ""; - display: table; - clear: both; } - .ct-perfect-fourth > svg { - display: block; - position: absolute; - top: 0; - left: 0; } - -.ct-perfect-fifth { - display: block; - position: relative; - width: 100%; } - .ct-perfect-fifth:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 66.66667%; } - .ct-perfect-fifth:after { - content: ""; - display: table; - clear: both; } - .ct-perfect-fifth > svg { - display: block; - position: absolute; - top: 0; - left: 0; } - -.ct-minor-sixth { - display: block; - position: relative; - width: 100%; } - .ct-minor-sixth:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 62.5%; } - .ct-minor-sixth:after { - content: ""; - display: table; - clear: both; } - .ct-minor-sixth > svg { - display: block; - position: absolute; - top: 0; - left: 0; } - -.ct-golden-section { - display: block; - position: relative; - width: 100%; } - .ct-golden-section:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 61.8047%; } - .ct-golden-section:after { - content: ""; - display: table; - clear: both; } - .ct-golden-section > svg { - display: block; - position: absolute; - top: 0; - left: 0; } - -.ct-major-sixth { - display: block; - position: relative; - width: 100%; } - .ct-major-sixth:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 60%; } - .ct-major-sixth:after { - content: ""; - display: table; - clear: both; } - .ct-major-sixth > svg { - display: block; - position: absolute; - top: 0; - left: 0; } - -.ct-minor-seventh { - display: block; - position: relative; - width: 100%; } - .ct-minor-seventh:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 56.25%; } - .ct-minor-seventh:after { - content: ""; - display: table; - clear: both; } - .ct-minor-seventh > svg { - display: block; - position: absolute; - top: 0; - left: 0; } - -.ct-major-seventh { - display: block; - position: relative; - width: 100%; } - .ct-major-seventh:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 53.33333%; } - .ct-major-seventh:after { - content: ""; - display: table; - clear: both; } - .ct-major-seventh > svg { - display: block; - position: absolute; - top: 0; - left: 0; } - -.ct-octave { - display: block; - position: relative; - width: 100%; } - .ct-octave:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 50%; } - .ct-octave:after { - content: ""; - display: table; - clear: both; } - .ct-octave > svg { - display: block; - position: absolute; - top: 0; - left: 0; } - -.ct-major-tenth { - display: block; - position: relative; - width: 100%; } - .ct-major-tenth:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 40%; } - .ct-major-tenth:after { - content: ""; - display: table; - clear: both; } - .ct-major-tenth > svg { - display: block; - position: absolute; - top: 0; - left: 0; } - -.ct-major-eleventh { - display: block; - position: relative; - width: 100%; } - .ct-major-eleventh:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 37.5%; } - .ct-major-eleventh:after { - content: ""; - display: table; - clear: both; } - .ct-major-eleventh > svg { - display: block; - position: absolute; - top: 0; - left: 0; } - -.ct-major-twelfth { - display: block; - position: relative; - width: 100%; } - .ct-major-twelfth:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 33.33333%; } - .ct-major-twelfth:after { - content: ""; - display: table; - clear: both; } - .ct-major-twelfth > svg { - display: block; - position: absolute; - top: 0; - left: 0; } - -.ct-double-octave { - display: block; - position: relative; - width: 100%; } - .ct-double-octave:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: 25%; } - .ct-double-octave:after { - content: ""; - display: table; - clear: both; } - .ct-double-octave > svg { - display: block; - position: absolute; - top: 0; - left: 0; } - -@media (min-width: 992px) { - .navbar-form { - margin-top: 21px; - margin-bottom: 21px; - padding-left: 5px; - padding-right: 5px; } - - .navbar-nav > li > .dropdown-menu, .dropdown .dropdown-menu { - -webkit-transform: scale(0); - -moz-transform: scale(0); - -o-transform: scale(0); - -ms-transform: scale(0); - transform: scale(0); - -webkit-transition: all 370ms cubic-bezier(0.34, 1.61, 0.7, 1); - -moz-transition: all 370ms cubic-bezier(0.34, 1.61, 0.7, 1); - -o-transition: all 370ms cubic-bezier(0.34, 1.61, 0.7, 1); - -ms-transition: all 370ms cubic-bezier(0.34, 1.61, 0.7, 1); - transition: all 370ms cubic-bezier(0.34, 1.61, 0.7, 1); } - - .navbar-nav > li.open > .dropdown-menu, .dropdown.open .dropdown-menu { - -webkit-transform: scale(1); - -moz-transform: scale(1); - -o-transform: scale(1); - -ms-transform: scale(1); - transform: scale(1); - -webkit-transform-origin: 29px -50px; - -moz-transform-origin: 29px -50px; - -o-transform-origin: 29px -50px; - -ms-transform-origin: 29px -50px; - transform-origin: 29px -50px; } - - .navbar-nav > li > .dropdown-menu:before { - border-bottom: 11px solid rgba(0, 0, 0, 0.2); - border-left: 11px solid transparent; - border-right: 11px solid transparent; - content: ""; - display: inline-block; - position: absolute; - left: 12px; - top: -11px; } - - .navbar-nav > li > .dropdown-menu:after { - border-bottom: 11px solid #FFFFFF; - border-left: 11px solid transparent; - border-right: 11px solid transparent; - content: ""; - display: inline-block; - position: absolute; - left: 12px; - top: -10px; } - - .navbar-nav.navbar-right > li > .dropdown-menu:before { - left: auto; - right: 12px; } - - .navbar-nav.navbar-right > li > .dropdown-menu:after { - left: auto; - right: 12px; } - - .footer:not(.footer-big) nav > ul li:first-child { - margin-left: 0; } - - body > .navbar-collapse.collapse { - display: none !important; } - - .card form [class*="col-"] { - padding: 6px; } - .card form [class*="col-"]:first-child { - padding-left: 15px; } - .card form [class*="col-"]:last-child { - padding-right: 15px; } } -/* Changes for small display */ -@media (max-width: 991px) { - .sidebar { - display: none; } - - .main-panel { - width: 100%; } - - .navbar-transparent { - padding-top: 15px; - background-color: rgba(0, 0, 0, 0.45); } - - body { - position: relative; } - - .wrapper { - -webkit-transform: translate3d(0px, 0, 0); - -moz-transform: translate3d(0px, 0, 0); - -o-transform: translate3d(0px, 0, 0); - -ms-transform: translate3d(0px, 0, 0); - transform: translate3d(0px, 0, 0); - -webkit-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1); - -moz-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1); - -o-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1); - -ms-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1); - transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1); - left: 0; - background-color: white; } - - .navbar .container { - left: 0; - width: 100%; - -webkit-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1); - -moz-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1); - -o-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1); - -ms-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1); - transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1); - position: relative; } - - .navbar .navbar-collapse.collapse, - .navbar .navbar-collapse.collapse.in, - .navbar .navbar-collapse.collapsing { - display: none !important; } - - .navbar-nav > li { - float: none; - position: relative; - display: block; } - - body > .navbar-collapse { - position: fixed; - display: block; - top: 0; - height: 100%; - width: 250px; - right: 0; - z-index: 1032; - visibility: visible; - background-color: #999; - overflow-y: visible; - border-top: none; - text-align: left; - padding: 0; - -webkit-transform: translate3d(250px, 0, 0); - -moz-transform: translate3d(250px, 0, 0); - -o-transform: translate3d(250px, 0, 0); - -ms-transform: translate3d(250px, 0, 0); - transform: translate3d(250px, 0, 0); - -webkit-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1); - -moz-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1); - -o-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1); - -ms-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1); - transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1); } - body > .navbar-collapse > ul { - position: relative; - z-index: 4; - overflow-y: scroll; - height: calc(100vh - 61px); - width: 100%; } - body > .navbar-collapse .nav > li > a { - padding: 30px 25px; } - body > .navbar-collapse::before { - top: 0; - left: 0; - height: 100%; - width: 100%; - position: absolute; - background-color: #282828; - display: block; - content: ""; - z-index: 1; } - body > .navbar-collapse .logo { - position: relative; - z-index: 4; } - - .nav-open .navbar-collapse { - -webkit-transform: translate3d(0px, 0, 0); - -moz-transform: translate3d(0px, 0, 0); - -o-transform: translate3d(0px, 0, 0); - -ms-transform: translate3d(0px, 0, 0); - transform: translate3d(0px, 0, 0); } - - .nav-open .navbar .container { - left: -250px; } - - .nav-open .wrapper { - left: 0; - -webkit-transform: translate3d(-250px, 0, 0); - -moz-transform: translate3d(-250px, 0, 0); - -o-transform: translate3d(-250px, 0, 0); - -ms-transform: translate3d(-250px, 0, 0); - transform: translate3d(-250px, 0, 0); } - - .navbar-toggle .icon-bar { - display: block; - position: relative; - background: #fff; - width: 24px; - height: 2px; - border-radius: 1px; - margin: 0 auto; } - - .navbar-header .navbar-toggle { - margin: 10px 15px 10px 0; - width: 40px; - height: 40px; } - - .bar1, - .bar2, - .bar3 { - outline: 1px solid transparent; } - - .bar1 { - top: 0px; - -webkit-animation: topbar-back 500ms linear 0s; - -moz-animation: topbar-back 500ms linear 0s; - animation: topbar-back 500ms 0s; - -webkit-animation-fill-mode: forwards; - -moz-animation-fill-mode: forwards; - animation-fill-mode: forwards; } - - .bar2 { - opacity: 1; } - - .bar3 { - bottom: 0px; - -webkit-animation: bottombar-back 500ms linear 0s; - -moz-animation: bottombar-back 500ms linear 0s; - animation: bottombar-back 500ms 0s; - -webkit-animation-fill-mode: forwards; - -moz-animation-fill-mode: forwards; - animation-fill-mode: forwards; } - - .toggled .bar1 { - top: 6px; - -webkit-animation: topbar-x 500ms linear 0s; - -moz-animation: topbar-x 500ms linear 0s; - animation: topbar-x 500ms 0s; - -webkit-animation-fill-mode: forwards; - -moz-animation-fill-mode: forwards; - animation-fill-mode: forwards; } - - .toggled .bar2 { - opacity: 0; } - - .toggled .bar3 { - bottom: 6px; - -webkit-animation: bottombar-x 500ms linear 0s; - -moz-animation: bottombar-x 500ms linear 0s; - animation: bottombar-x 500ms 0s; - -webkit-animation-fill-mode: forwards; - -moz-animation-fill-mode: forwards; - animation-fill-mode: forwards; } - - @keyframes topbar-x { - 0% { - top: 0px; - transform: rotate(0deg); } - 45% { - top: 6px; - transform: rotate(145deg); } - 75% { - transform: rotate(130deg); } - 100% { - transform: rotate(135deg); } } - @-webkit-keyframes topbar-x { - 0% { - top: 0px; - -webkit-transform: rotate(0deg); } - 45% { - top: 6px; - -webkit-transform: rotate(145deg); } - 75% { - -webkit-transform: rotate(130deg); } - 100% { - -webkit-transform: rotate(135deg); } } - @-moz-keyframes topbar-x { - 0% { - top: 0px; - -moz-transform: rotate(0deg); } - 45% { - top: 6px; - -moz-transform: rotate(145deg); } - 75% { - -moz-transform: rotate(130deg); } - 100% { - -moz-transform: rotate(135deg); } } - @keyframes topbar-back { - 0% { - top: 6px; - transform: rotate(135deg); } - 45% { - transform: rotate(-10deg); } - 75% { - transform: rotate(5deg); } - 100% { - top: 0px; - transform: rotate(0); } } - @-webkit-keyframes topbar-back { - 0% { - top: 6px; - -webkit-transform: rotate(135deg); } - 45% { - -webkit-transform: rotate(-10deg); } - 75% { - -webkit-transform: rotate(5deg); } - 100% { - top: 0px; - -webkit-transform: rotate(0); } } - @-moz-keyframes topbar-back { - 0% { - top: 6px; - -moz-transform: rotate(135deg); } - 45% { - -moz-transform: rotate(-10deg); } - 75% { - -moz-transform: rotate(5deg); } - 100% { - top: 0px; - -moz-transform: rotate(0); } } - @keyframes bottombar-x { - 0% { - bottom: 0px; - transform: rotate(0deg); } - 45% { - bottom: 6px; - transform: rotate(-145deg); } - 75% { - transform: rotate(-130deg); } - 100% { - transform: rotate(-135deg); } } - @-webkit-keyframes bottombar-x { - 0% { - bottom: 0px; - -webkit-transform: rotate(0deg); } - 45% { - bottom: 6px; - -webkit-transform: rotate(-145deg); } - 75% { - -webkit-transform: rotate(-130deg); } - 100% { - -webkit-transform: rotate(-135deg); } } - @-moz-keyframes bottombar-x { - 0% { - bottom: 0px; - -moz-transform: rotate(0deg); } - 45% { - bottom: 6px; - -moz-transform: rotate(-145deg); } - 75% { - -moz-transform: rotate(-130deg); } - 100% { - -moz-transform: rotate(-135deg); } } - @keyframes bottombar-back { - 0% { - bottom: 6px; - transform: rotate(-135deg); } - 45% { - transform: rotate(10deg); } - 75% { - transform: rotate(-5deg); } - 100% { - bottom: 0px; - transform: rotate(0); } } - @-webkit-keyframes bottombar-back { - 0% { - bottom: 6px; - -webkit-transform: rotate(-135deg); } - 45% { - -webkit-transform: rotate(10deg); } - 75% { - -webkit-transform: rotate(-5deg); } - 100% { - bottom: 0px; - -webkit-transform: rotate(0); } } - @-moz-keyframes bottombar-back { - 0% { - bottom: 6px; - -moz-transform: rotate(-135deg); } - 45% { - -moz-transform: rotate(10deg); } - 75% { - -moz-transform: rotate(-5deg); } - 100% { - bottom: 0px; - -moz-transform: rotate(0); } } - @-webkit-keyframes fadeIn { - 0% { - opacity: 0; } - 100% { - opacity: 1; } } - @-moz-keyframes fadeIn { - 0% { - opacity: 0; } - 100% { - opacity: 1; } } - @keyframes fadeIn { - 0% { - opacity: 0; } - 100% { - opacity: 1; } } - .dropdown-menu .divider { - background-color: rgba(229, 229, 229, 0.15); } - - .navbar-nav { - margin: 1px 0; } - .navbar-nav .open .dropdown-menu > li > a { - padding: 15px 15px 5px 50px; } - .navbar-nav .open .dropdown-menu > li:first-child > a { - padding: 5px 15px 5px 50px; } - .navbar-nav .open .dropdown-menu > li:last-child > a { - padding: 15px 15px 25px 50px; } - - [class*="navbar-"] .navbar-nav > li > a, - [class*="navbar-"] .navbar-nav > li > a:hover, - [class*="navbar-"] .navbar-nav > li > a:focus, - [class*="navbar-"] .navbar-nav .active > a, - [class*="navbar-"] .navbar-nav .active > a:hover, - [class*="navbar-"] .navbar-nav .active > a:focus, - [class*="navbar-"] .navbar-nav .open .dropdown-menu > li > a, - [class*="navbar-"] .navbar-nav .open .dropdown-menu > li > a:hover, - [class*="navbar-"] .navbar-nav .open .dropdown-menu > li > a:focus, - [class*="navbar-"] .navbar-nav .navbar-nav .open .dropdown-menu > li > a:active { - color: white; } - [class*="navbar-"] .navbar-nav > li > a, - [class*="navbar-"] .navbar-nav > li > a:hover, - [class*="navbar-"] .navbar-nav > li > a:focus, - [class*="navbar-"] .navbar-nav .open .dropdown-menu > li > a, - [class*="navbar-"] .navbar-nav .open .dropdown-menu > li > a:hover, - [class*="navbar-"] .navbar-nav .open .dropdown-menu > li > a:focus { - opacity: .7; - background: transparent; } - [class*="navbar-"] .navbar-nav.navbar-nav .open .dropdown-menu > li > a:active { - opacity: 1; } - [class*="navbar-"] .navbar-nav .dropdown > a:hover .caret { - border-bottom-color: #777; - border-top-color: #777; } - [class*="navbar-"] .navbar-nav .dropdown > a:active .caret { - border-bottom-color: white; - border-top-color: white; } - - .dropdown-menu { - display: none; } - - .navbar-fixed-top { - -webkit-backface-visibility: hidden; } - - #bodyClick { - height: 100%; - width: 100%; - position: fixed; - opacity: 0; - top: 0; - left: auto; - right: 250px; - content: ""; - z-index: 9999; - overflow-x: hidden; } - - .social-line .btn { - margin: 0 0 10px 0; } - - .subscribe-line .form-control { - margin: 0 0 10px 0; } - - .social-line.pull-right { - float: none; } - - .footer nav.pull-left { - float: none !important; } - - .footer:not(.footer-big) nav > ul li { - float: none; } - - .social-area.pull-right { - float: none !important; } - - .form-control + .form-control-feedback { - margin-top: -8px; } - - .navbar-toggle:hover, .navbar-toggle:focus { - background-color: transparent !important; } - - .btn.dropdown-toggle { - margin-bottom: 0; } - - .media-post .author { - width: 20%; - float: none !important; - display: block; - margin: 0 auto 10px; } - - .media-post .media-body { - width: 100%; } - - .navbar-collapse.collapse { - height: 100% !important; } - - .navbar-collapse.collapse.in { - display: block; } - - .navbar-header .collapse, .navbar-toggle { - display: block !important; } - - .navbar-header { - float: none; } - - .navbar-nav .open .dropdown-menu { - position: static; - float: none; - width: auto; - margin-top: 0; - background-color: transparent; - border: 0; - -webkit-box-shadow: none; - box-shadow: none; } - - .navbar-collapse .nav p { - font-size: 14px; - margin: 0; } - .navbar-collapse [class^="pe-7s-"] { - float: left; - font-size: 20px; - margin-right: 10px; } } -@media (min-width: 992px) { - .table-full-width { - margin-left: -15px; - margin-right: -15px; } - - .table-responsive { - overflow: visible; } } -@media (max-width: 991px) { - .table-responsive { - width: 100%; - margin-bottom: 15px; - overflow-x: scroll; - overflow-y: hidden; - -ms-overflow-style: -ms-autohiding-scrollbar; - -webkit-overflow-scrolling: touch; } } diff --git a/frontend/assets/css/font-awesome.min.css b/frontend/assets/css/font-awesome.min.css deleted file mode 100644 index ec53d4d6..00000000 --- a/frontend/assets/css/font-awesome.min.css +++ /dev/null @@ -1,4 +0,0 @@ -/*! - * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome - * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.2.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff?v=4.2.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.2.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"} \ No newline at end of file diff --git a/frontend/assets/css/fonts.css b/frontend/assets/css/fonts.css deleted file mode 100644 index dab771f7..00000000 --- a/frontend/assets/css/fonts.css +++ /dev/null @@ -1,18 +0,0 @@ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v15/Hgo13k-tfSpn0qi1SFdUfaCWcynf_cDxXwCLxiixG1c.ttf) format('truetype'); -} -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v15/zN7GBFwfMP4uA6AR0HCoLQ.ttf) format('truetype'); -} -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v15/d-6IYplOFocCacKzxwXSOKCWcynf_cDxXwCLxiixG1c.ttf) format('truetype'); -} diff --git a/frontend/assets/css/pe-icon-7-stroke.css b/frontend/assets/css/pe-icon-7-stroke.css deleted file mode 100755 index 44bcbaa6..00000000 --- a/frontend/assets/css/pe-icon-7-stroke.css +++ /dev/null @@ -1,632 +0,0 @@ -@font-face { - font-family: 'Pe-icon-7-stroke'; - src:url('../fonts/Pe-icon-7-stroke.eot?d7yf1v'); - src:url('../fonts/Pe-icon-7-stroke.eot?#iefixd7yf1v') format('embedded-opentype'), - url('../fonts/Pe-icon-7-stroke.woff?d7yf1v') format('woff'), - url('../fonts/Pe-icon-7-stroke.ttf?d7yf1v') format('truetype'), - url('../fonts/Pe-icon-7-stroke.svg?d7yf1v#Pe-icon-7-stroke') format('svg'); - font-weight: normal; - font-style: normal; -} - -[class^="pe-7s-"], [class*=" pe-7s-"] { - display: inline-block; - font-family: 'Pe-icon-7-stroke'; - speak: none; - font-style: normal; - font-weight: normal; - font-variant: normal; - text-transform: none; - line-height: 1; - - /* Better Font Rendering =========== */ - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.pe-7s-album:before { - content: "\e6aa"; -} -.pe-7s-arc:before { - content: "\e6ab"; -} -.pe-7s-back-2:before { - content: "\e6ac"; -} -.pe-7s-bandaid:before { - content: "\e6ad"; -} -.pe-7s-car:before { - content: "\e6ae"; -} -.pe-7s-diamond:before { - content: "\e6af"; -} -.pe-7s-door-lock:before { - content: "\e6b0"; -} -.pe-7s-eyedropper:before { - content: "\e6b1"; -} -.pe-7s-female:before { - content: "\e6b2"; -} -.pe-7s-gym:before { - content: "\e6b3"; -} -.pe-7s-hammer:before { - content: "\e6b4"; -} -.pe-7s-headphones:before { - content: "\e6b5"; -} -.pe-7s-helm:before { - content: "\e6b6"; -} -.pe-7s-hourglass:before { - content: "\e6b7"; -} -.pe-7s-leaf:before { - content: "\e6b8"; -} -.pe-7s-magic-wand:before { - content: "\e6b9"; -} -.pe-7s-male:before { - content: "\e6ba"; -} -.pe-7s-map-2:before { - content: "\e6bb"; -} -.pe-7s-next-2:before { - content: "\e6bc"; -} -.pe-7s-paint-bucket:before { - content: "\e6bd"; -} -.pe-7s-pendrive:before { - content: "\e6be"; -} -.pe-7s-photo:before { - content: "\e6bf"; -} -.pe-7s-piggy:before { - content: "\e6c0"; -} -.pe-7s-plugin:before { - content: "\e6c1"; -} -.pe-7s-refresh-2:before { - content: "\e6c2"; -} -.pe-7s-rocket:before { - content: "\e6c3"; -} -.pe-7s-settings:before { - content: "\e6c4"; -} -.pe-7s-shield:before { - content: "\e6c5"; -} -.pe-7s-smile:before { - content: "\e6c6"; -} -.pe-7s-usb:before { - content: "\e6c7"; -} -.pe-7s-vector:before { - content: "\e6c8"; -} -.pe-7s-wine:before { - content: "\e6c9"; -} -.pe-7s-cloud-upload:before { - content: "\e68a"; -} -.pe-7s-cash:before { - content: "\e68c"; -} -.pe-7s-close:before { - content: "\e680"; -} -.pe-7s-bluetooth:before { - content: "\e68d"; -} -.pe-7s-cloud-download:before { - content: "\e68b"; -} -.pe-7s-way:before { - content: "\e68e"; -} -.pe-7s-close-circle:before { - content: "\e681"; -} -.pe-7s-id:before { - content: "\e68f"; -} -.pe-7s-angle-up:before { - content: "\e682"; -} -.pe-7s-wristwatch:before { - content: "\e690"; -} -.pe-7s-angle-up-circle:before { - content: "\e683"; -} -.pe-7s-world:before { - content: "\e691"; -} -.pe-7s-angle-right:before { - content: "\e684"; -} -.pe-7s-volume:before { - content: "\e692"; -} -.pe-7s-angle-right-circle:before { - content: "\e685"; -} -.pe-7s-users:before { - content: "\e693"; -} -.pe-7s-angle-left:before { - content: "\e686"; -} -.pe-7s-user-female:before { - content: "\e694"; -} -.pe-7s-angle-left-circle:before { - content: "\e687"; -} -.pe-7s-up-arrow:before { - content: "\e695"; -} -.pe-7s-angle-down:before { - content: "\e688"; -} -.pe-7s-switch:before { - content: "\e696"; -} -.pe-7s-angle-down-circle:before { - content: "\e689"; -} -.pe-7s-scissors:before { - content: "\e697"; -} -.pe-7s-wallet:before { - content: "\e600"; -} -.pe-7s-safe:before { - content: "\e698"; -} -.pe-7s-volume2:before { - content: "\e601"; -} -.pe-7s-volume1:before { - content: "\e602"; -} -.pe-7s-voicemail:before { - content: "\e603"; -} -.pe-7s-video:before { - content: "\e604"; -} -.pe-7s-user:before { - content: "\e605"; -} -.pe-7s-upload:before { - content: "\e606"; -} -.pe-7s-unlock:before { - content: "\e607"; -} -.pe-7s-umbrella:before { - content: "\e608"; -} -.pe-7s-trash:before { - content: "\e609"; -} -.pe-7s-tools:before { - content: "\e60a"; -} -.pe-7s-timer:before { - content: "\e60b"; -} -.pe-7s-ticket:before { - content: "\e60c"; -} -.pe-7s-target:before { - content: "\e60d"; -} -.pe-7s-sun:before { - content: "\e60e"; -} -.pe-7s-study:before { - content: "\e60f"; -} -.pe-7s-stopwatch:before { - content: "\e610"; -} -.pe-7s-star:before { - content: "\e611"; -} -.pe-7s-speaker:before { - content: "\e612"; -} -.pe-7s-signal:before { - content: "\e613"; -} -.pe-7s-shuffle:before { - content: "\e614"; -} -.pe-7s-shopbag:before { - content: "\e615"; -} -.pe-7s-share:before { - content: "\e616"; -} -.pe-7s-server:before { - content: "\e617"; -} -.pe-7s-search:before { - content: "\e618"; -} -.pe-7s-film:before { - content: "\e6a5"; -} -.pe-7s-science:before { - content: "\e619"; -} -.pe-7s-disk:before { - content: "\e6a6"; -} -.pe-7s-ribbon:before { - content: "\e61a"; -} -.pe-7s-repeat:before { - content: "\e61b"; -} -.pe-7s-refresh:before { - content: "\e61c"; -} -.pe-7s-add-user:before { - content: "\e6a9"; -} -.pe-7s-refresh-cloud:before { - content: "\e61d"; -} -.pe-7s-paperclip:before { - content: "\e69c"; -} -.pe-7s-radio:before { - content: "\e61e"; -} -.pe-7s-note2:before { - content: "\e69d"; -} -.pe-7s-print:before { - content: "\e61f"; -} -.pe-7s-network:before { - content: "\e69e"; -} -.pe-7s-prev:before { - content: "\e620"; -} -.pe-7s-mute:before { - content: "\e69f"; -} -.pe-7s-power:before { - content: "\e621"; -} -.pe-7s-medal:before { - content: "\e6a0"; -} -.pe-7s-portfolio:before { - content: "\e622"; -} -.pe-7s-like2:before { - content: "\e6a1"; -} -.pe-7s-plus:before { - content: "\e623"; -} -.pe-7s-left-arrow:before { - content: "\e6a2"; -} -.pe-7s-play:before { - content: "\e624"; -} -.pe-7s-key:before { - content: "\e6a3"; -} -.pe-7s-plane:before { - content: "\e625"; -} -.pe-7s-joy:before { - content: "\e6a4"; -} -.pe-7s-photo-gallery:before { - content: "\e626"; -} -.pe-7s-pin:before { - content: "\e69b"; -} -.pe-7s-phone:before { - content: "\e627"; -} -.pe-7s-plug:before { - content: "\e69a"; -} -.pe-7s-pen:before { - content: "\e628"; -} -.pe-7s-right-arrow:before { - content: "\e699"; -} -.pe-7s-paper-plane:before { - content: "\e629"; -} -.pe-7s-delete-user:before { - content: "\e6a7"; -} -.pe-7s-paint:before { - content: "\e62a"; -} -.pe-7s-bottom-arrow:before { - content: "\e6a8"; -} -.pe-7s-notebook:before { - content: "\e62b"; -} -.pe-7s-note:before { - content: "\e62c"; -} -.pe-7s-next:before { - content: "\e62d"; -} -.pe-7s-news-paper:before { - content: "\e62e"; -} -.pe-7s-musiclist:before { - content: "\e62f"; -} -.pe-7s-music:before { - content: "\e630"; -} -.pe-7s-mouse:before { - content: "\e631"; -} -.pe-7s-more:before { - content: "\e632"; -} -.pe-7s-moon:before { - content: "\e633"; -} -.pe-7s-monitor:before { - content: "\e634"; -} -.pe-7s-micro:before { - content: "\e635"; -} -.pe-7s-menu:before { - content: "\e636"; -} -.pe-7s-map:before { - content: "\e637"; -} -.pe-7s-map-marker:before { - content: "\e638"; -} -.pe-7s-mail:before { - content: "\e639"; -} -.pe-7s-mail-open:before { - content: "\e63a"; -} -.pe-7s-mail-open-file:before { - content: "\e63b"; -} -.pe-7s-magnet:before { - content: "\e63c"; -} -.pe-7s-loop:before { - content: "\e63d"; -} -.pe-7s-look:before { - content: "\e63e"; -} -.pe-7s-lock:before { - content: "\e63f"; -} -.pe-7s-lintern:before { - content: "\e640"; -} -.pe-7s-link:before { - content: "\e641"; -} -.pe-7s-like:before { - content: "\e642"; -} -.pe-7s-light:before { - content: "\e643"; -} -.pe-7s-less:before { - content: "\e644"; -} -.pe-7s-keypad:before { - content: "\e645"; -} -.pe-7s-junk:before { - content: "\e646"; -} -.pe-7s-info:before { - content: "\e647"; -} -.pe-7s-home:before { - content: "\e648"; -} -.pe-7s-help2:before { - content: "\e649"; -} -.pe-7s-help1:before { - content: "\e64a"; -} -.pe-7s-graph3:before { - content: "\e64b"; -} -.pe-7s-graph2:before { - content: "\e64c"; -} -.pe-7s-graph1:before { - content: "\e64d"; -} -.pe-7s-graph:before { - content: "\e64e"; -} -.pe-7s-global:before { - content: "\e64f"; -} -.pe-7s-gleam:before { - content: "\e650"; -} -.pe-7s-glasses:before { - content: "\e651"; -} -.pe-7s-gift:before { - content: "\e652"; -} -.pe-7s-folder:before { - content: "\e653"; -} -.pe-7s-flag:before { - content: "\e654"; -} -.pe-7s-filter:before { - content: "\e655"; -} -.pe-7s-file:before { - content: "\e656"; -} -.pe-7s-expand1:before { - content: "\e657"; -} -.pe-7s-exapnd2:before { - content: "\e658"; -} -.pe-7s-edit:before { - content: "\e659"; -} -.pe-7s-drop:before { - content: "\e65a"; -} -.pe-7s-drawer:before { - content: "\e65b"; -} -.pe-7s-download:before { - content: "\e65c"; -} -.pe-7s-display2:before { - content: "\e65d"; -} -.pe-7s-display1:before { - content: "\e65e"; -} -.pe-7s-diskette:before { - content: "\e65f"; -} -.pe-7s-date:before { - content: "\e660"; -} -.pe-7s-cup:before { - content: "\e661"; -} -.pe-7s-culture:before { - content: "\e662"; -} -.pe-7s-crop:before { - content: "\e663"; -} -.pe-7s-credit:before { - content: "\e664"; -} -.pe-7s-copy-file:before { - content: "\e665"; -} -.pe-7s-config:before { - content: "\e666"; -} -.pe-7s-compass:before { - content: "\e667"; -} -.pe-7s-comment:before { - content: "\e668"; -} -.pe-7s-coffee:before { - content: "\e669"; -} -.pe-7s-cloud:before { - content: "\e66a"; -} -.pe-7s-clock:before { - content: "\e66b"; -} -.pe-7s-check:before { - content: "\e66c"; -} -.pe-7s-chat:before { - content: "\e66d"; -} -.pe-7s-cart:before { - content: "\e66e"; -} -.pe-7s-camera:before { - content: "\e66f"; -} -.pe-7s-call:before { - content: "\e670"; -} -.pe-7s-calculator:before { - content: "\e671"; -} -.pe-7s-browser:before { - content: "\e672"; -} -.pe-7s-box2:before { - content: "\e673"; -} -.pe-7s-box1:before { - content: "\e674"; -} -.pe-7s-bookmarks:before { - content: "\e675"; -} -.pe-7s-bicycle:before { - content: "\e676"; -} -.pe-7s-bell:before { - content: "\e677"; -} -.pe-7s-battery:before { - content: "\e678"; -} -.pe-7s-ball:before { - content: "\e679"; -} -.pe-7s-back:before { - content: "\e67a"; -} -.pe-7s-attention:before { - content: "\e67b"; -} -.pe-7s-anchor:before { - content: "\e67c"; -} -.pe-7s-albums:before { - content: "\e67d"; -} -.pe-7s-alarm:before { - content: "\e67e"; -} -.pe-7s-airplay:before { - content: "\e67f"; -} diff --git a/frontend/assets/fonts/Pe-icon-7-stroke.eot b/frontend/assets/fonts/Pe-icon-7-stroke.eot deleted file mode 100755 index 6f7b58489c6fe76af1597fad93bd8ebe36114eb9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58680 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 Nxi7{(cl`%H{|#3vvLpZi diff --git a/frontend/assets/fonts/Pe-icon-7-stroke.svg b/frontend/assets/fonts/Pe-icon-7-stroke.svg deleted file mode 100755 index 13d9709a..00000000 --- a/frontend/assets/fonts/Pe-icon-7-stroke.svg +++ /dev/null @@ -1,212 +0,0 @@ - - - -Generated by IcoMoon - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/frontend/assets/fonts/Pe-icon-7-stroke.ttf b/frontend/assets/fonts/Pe-icon-7-stroke.ttf deleted file mode 100755 index bc8a269c68dafaaf5aaa7920e7a17baff0748360..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58480 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 XVssBJ#01M7olcSaV(fF*fAI6)u)>;0 diff --git a/frontend/assets/fonts/Pe-icon-7-stroke.woff b/frontend/assets/fonts/Pe-icon-7-stroke.woff deleted file mode 100755 index c205e6fd3cae5dbfd991d499c7495c9228a804c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58556 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 diff --git a/frontend/assets/img/mask.png b/frontend/assets/img/mask.png deleted file mode 100755 index 429360d5ce730f002b7413fdb94bcd261339b5ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 756 zcmeAS@N?(olHy`uVBq!ia0vp^0YEIv!NkD8cyyD`Js^j(z$3Dlfq`2Xgc%uT&5-~K zDkOUZ`7$u%&R}3D?qgv1b%ueV3kcwML zKmLP({*A-*E2LeiU=QJ1RAk@^Je8B|IkoT7jCe!ITtr_Iw7T7H-mN|a>_~Iq6)cxmOxaCz}U%#Ui=s2K3N3I^^Y%vgEy)dEq$tzzSg&VCE z-hNH8D(cxBVu|TZ(-bt7gnr7EDXw`FXuQACea6q3EX)??i)Ss{wNCy>i$Lu4wXeJG zt5is|ZI6GmcmLtk$Y+utw&ikeyY?(*od6RG}N|3)b--Fx0`gf zzb;_}x%SBnuxnk_#RT?9>t``*iRooAcc!mZnAfW+aiSt1qKtFX^3=I|_~e*B|L0l2 zpZ(T=$M^C9X3f)^UR!0a4SyS4G4HvFZzGFS$8JvPnb8pYyQ0%A4xY&>OYj9^0NMc%^60)#}<5!Gm85<1XFVdQ&MBb@031k3nE(I) diff --git a/frontend/assets/img/nomad.jpg b/frontend/assets/img/nomad.jpg deleted file mode 100644 index 79ead7f1c7a303cd36316bd94ceb507d842f0f67..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 437643 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

    a5|`kz+D<1>|M>gP{+u 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%0Db^$3&7EMKvji&N|LIyzF;=Dw!}jmU+p{Bc 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 z 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

    }YC!1MjU*4bjz(-eiT5}Xn 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 T4@?kWEpbGrO($4mVYn$>n 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

    AWB_O2#t}6 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 z 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 m=p)1+DELl33cf@$ArCP(k(LIU#xoPuiRt+ diff --git a/frontend/assets/nomad-ui.css b/frontend/assets/nomad-ui.css new file mode 100644 index 00000000..37e76b15 --- /dev/null +++ b/frontend/assets/nomad-ui.css @@ -0,0 +1,22 @@ +html { + font-family: 'Roboto', sans-serif; + -webkit-font-smoothing: antialiased; +} + +body { + font-size: 15px; + line-height: 24px; + margin: 0; +} + +body, h1, h2, h3, h4, h5, h6 { + margin: 0; +} + +a { + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} diff --git a/frontend/assets/sass/nomad-ui.scss b/frontend/assets/sass/nomad-ui.scss deleted file mode 100755 index 8c7fff96..00000000 --- a/frontend/assets/sass/nomad-ui.scss +++ /dev/null @@ -1,185 +0,0 @@ -// variables and mixins -@import "nomad-ui/variables"; -@import "nomad-ui/mixins"; - -//plugins css -// @import "nomad-ui/plugins/animate"; -// @import "nomad-ui/plugins/sweetalert2"; - -// @import "nomad-ui/plugins/jquery.jvectormap"; -// @import "nomad-ui/plugins/bootstrap-table"; -// @import "nomad-ui/plugins/datatables.net"; -// @import "nomad-ui/plugins/fullcalendar"; -// @import "nomad-ui/plugins/chartist"; -// @import "nomad-ui/plugins/perfect-scrollbar"; -// @import "nomad-ui/plugins/bootstrap-select"; - -// Core CSS -@import "nomad-ui/typography"; -@import "nomad-ui/sidebar-and-main-panel"; -@import "nomad-ui/buttons"; -@import "nomad-ui/misc"; -@import "nomad-ui/inputs"; -// @import "nomad-ui/progress-bars"; -// @import "nomad-ui/sliders"; -@import "nomad-ui/forms"; -// @import "nomad-ui/alerts"; -@import "nomad-ui/tables"; -// @import "nomad-ui/tags"; -// @import "nomad-ui/tooltips-and-popovers"; -// @import "nomad-ui/checkbox-radio-switch"; -@import "nomad-ui/navbars"; -// @import "nomad-ui/footers"; - -// Fancy Stuff -// @import "nomad-ui/social-buttons"; -@import "nomad-ui/dropdown"; -@import "nomad-ui/cards"; -@import "nomad-ui/collapse"; -// @import "nomad-ui/carousel"; -// SCSS for Pages -// @import "nomad-ui/pages.scss"; - -// Responsive adjustments -@import "nomad-ui/responsive"; -@import "nomad-ui/tabs-navs-pagination"; - -.wrapper{ - position: relative; - top: 0; - height: 100vh; - - &:after{ - display: table; - clear: both; - content: " "; - } - - &.wrapper-full-page{ - height: auto; - min-height: 100vh; - } -} - -.pointer { - cursor: pointer; -} - -dl { - margin-bottom: 0; -} - -.dotted { - border-bottom: 1px dashed #999; - text-decoration: none; -} - -.no-border { - border: none -} - -.btn.no-border { - padding: 0 -} - -.dropdown-menu:before { - content: initial; -} - -.dropdown-menu:after { - content: initial; -} - -.header .btn-group { - padding-top: 15px; -} - -.inline-pad { - padding-bottom: 15px; - padding-left: 15px; -} - -.content > .inline-pad { - padding-left: 0; -} - -.statistics-big { - font-size: 150% -} - -.expand-left-menu { - top: 5px; - right: 5px; - position: absolute -} - -.sidebar .sidebar-background { - background-size: initial; - background-position: initial; -} - -.file-content-hr { - margin-bottom: 0px; - margin-top: 15px; -} - -.btn-download { - float: right; - line-height: 1em; -} - -form.file-download { - float: right; - line-height: 0; - margin-bottom: 0.5em; -} - -i.pe-7s-attention { - margin-right: 15px; - line-height: 1.5; -} - -span.file-size-warning { - line-height: 2; -} - -.tab-pane { - // padding-top: 0; -} - -.tab-column { - margin-bottom: 15px; -} - -.tab-content { - legend { - padding-left: 15px; - } - - padding: 15px; - padding-left: 0; - padding-top: 0; -} - -.nested-content { - .table-full-width { - margin-left: 0; - margin-right: -30px - } - - legend, - .panel-group { - padding-left: 15px - } -} - -.center { - text-align: center -} - -.content-file { - font-family: monospace; - font-size: 90%; - unicode-bidi: embed; - white-space: pre; -} diff --git a/frontend/assets/sass/nomad-ui/_alerts.scss b/frontend/assets/sass/nomad-ui/_alerts.scss deleted file mode 100644 index 3fbc267d..00000000 --- a/frontend/assets/sass/nomad-ui/_alerts.scss +++ /dev/null @@ -1,82 +0,0 @@ -.alert{ - border: 0; - border-radius: 0; - color: #FFFFFF; - padding: 10px 15px; - font-size: 14px; - - .container &{ - border-radius: 4px; - - } - .navbar &{ - border-radius: 0; - left: 0; - position: absolute; - right: 0; - top: 85px; - width: 100%; - z-index: 3; - } - .navbar:not(.navbar-transparent) &{ - top: 70px; - } - - span[data-notify="icon"]{ - font-size: 30px; - display: block; - left: 15px; - position: absolute; - top: 50%; - margin-top: -15px; - } - - button.close{ - position: absolute; - right: 10px; - top: 50%; - margin-top: -13px; - z-index: 1033; - background-color: #FFFFFF; - display: block; - border-radius: 50%; - opacity: .4; - line-height: 11px; - width: 25px; - height: 25px; - outline: 0 !important; - text-align: center; - padding: 3px; - font-weight: 300; - - &:hover{ - opacity: .55; - } - } - - .close ~ span{ - display: block; - max-width: 89%; - } - - &[data-notify="container"]{ - padding: 10px 10px 10px 20px; - border-radius: $border-radius-base; - } - - &.alert-with-icon{ - padding-left: 65px; - } -} -.alert-info{ - background-color: $azure-navbar; -} -.alert-success { - background-color: $green-navbar; -} -.alert-warning { - background-color: $orange-navbar; -} -.alert-danger { - background-color: $red-navbar; -} diff --git a/frontend/assets/sass/nomad-ui/_buttons.scss b/frontend/assets/sass/nomad-ui/_buttons.scss deleted file mode 100755 index d14f110a..00000000 --- a/frontend/assets/sass/nomad-ui/_buttons.scss +++ /dev/null @@ -1,123 +0,0 @@ -.btn{ - border-width: $border-thin; - background-color: $transparent-bg; - font-weight: $font-weight-normal; - - @include opacity(.8); - padding: $padding-base-vertical $padding-base-horizontal; - - @include btn-styles($default-color, $default-states-color); - - &:hover, - &:focus{ - @include opacity(1); - outline: 0 !important; - } - &:active, - &.active, - .open > &.dropdown-toggle { - @include box-shadow(none); - outline: 0 !important; - } - - &.btn-icon{ - padding: $padding-base-vertical; - } - - .btn-label{ - .fa{ - width: 13px; - } - } - - .fa{ - width: 20px; - } -} - -// Apply the mixin to the buttons -//.btn-default { @include btn-styles($default-color, $default-states-color); } -.btn-primary { @include btn-styles($primary-color, $primary-states-color); } -.btn-success { @include btn-styles($success-color, $success-states-color); } -.btn-info { @include btn-styles($info-color, $info-states-color); } -.btn-warning { @include btn-styles($warning-color, $warning-states-color); } -.btn-danger { @include btn-styles($danger-color, $danger-states-color); } - -.btn-neutral { - @include btn-styles($white-color, $white-color); - - &:active, - &.active, - .open > &.dropdown-toggle{ - background-color: $white-color; - color: $default-color; - } - - &.btn-fill, - &.btn-fill:hover, - &.btn-fill:focus{ - color: $default-color; - } - - &.btn-fill:hover, - &.btn-fill:focus{ - @include opacity(.86); - } - - &.btn-simple:active, - &.btn-simple.active{ - background-color: transparent; - } -} - -.btn{ - &:disabled, - &[disabled], - &.disabled{ - @include opacity(.5); - } -} -.btn-round{ - border-width: $border-thin; - border-radius: $btn-round-radius !important; - padding: $padding-round-vertical $padding-round-horizontal; - - &.btn-icon{ - padding: $padding-round-vertical; - } -} -.btn-simple{ - border: $none; - font-size: $font-size-medium; - padding: $padding-base-vertical $padding-base-horizontal; - - &.btn-icon{ - padding: $padding-base-vertical; - } -} -.btn-lg{ - @include btn-size($padding-large-vertical, $padding-large-horizontal, $font-size-large, $border-radius-large); - font-weight: $font-weight-normal; -} -.btn-sm{ - @include btn-size($padding-small-vertical, $padding-small-horizontal, $font-size-small, $border-radius-small); -} -.btn-xs { - @include btn-size($padding-xs-vertical, $padding-xs-horizontal, $font-size-small, $border-radius-small); -} -.btn-wd { - min-width: 140px; -} - -.btn-group.select{ - width: 100%; -} -.btn-group.select .btn{ - text-align: left; -} -.btn-group.select .caret{ - position: absolute; - top: 50%; - margin-top: -1px; - right: 8px; -} diff --git a/frontend/assets/sass/nomad-ui/_cards.scss b/frontend/assets/sass/nomad-ui/_cards.scss deleted file mode 100644 index a2d877c9..00000000 --- a/frontend/assets/sass/nomad-ui/_cards.scss +++ /dev/null @@ -1,322 +0,0 @@ -.card{ - border-radius: $border-radius-base; - box-shadow: 0 1px 2px rgba(0,0,0,.05),0 0 0 1px rgba(63,63,68,.1); - background-color: #FFFFFF; - margin-bottom: 30px; - -/* - background-image: url('https://images.unsplash.com/photo-1438978280647-f359d95ebda4?q=80&fm=jpg&s=73cb1239b517411534379c92660b2660'); - background-size: cover; - z-index: 1; - - &:before{ - position: absolute; - width: 94%; - left: 3%; - height: 95%; - z-index: 0; - background-color: red; - display: block; - border-radius: 6px; - content: ""; - box-shadow: 0 3px 40px rgba(0, 0, 0, 0.2); - top: 24px; - } -*/ - - .image{ - width: 100%; - overflow: hidden; - height: 260px; - border-radius: $border-radius-base $border-radius-base 0 0; - position: relative; - -webkit-transform-style: preserve-3d; - -moz-transform-style: preserve-3d; - transform-style: preserve-3d; - - img { - width: 100%; - } - } - .filter{ - position: absolute; - z-index: 2; - background-color: rgba(0,0,0,.68); - top: 0; - left: 0; - width: 100%; - height: 100%; - text-align: center; - - @include opacity(0); - - .btn{ - @include vertical-align(); - } - } - &:hover .filter{ - @include opacity(1); - } - .btn-hover{ - @include opacity(0); - } - &:hover .btn-hover{ - @include opacity(1); - } - .map { - height: 280px; - border-radius: $border-radius-base; - - &.map-big{ - height: 420px; - } - } - .content{ - padding: $padding-default-horizontal; - } - .content-file{ - height: 750px; - overflow: auto; - clear: both; - white-space: pre; - background: #f5f5f5; - } - .content-no-padding{ - padding: 0; - - .map{ - margin-top: $padding-default-horizontal; - border-radius: 0; - } - } - .content-full-width{ - padding: $padding-default-horizontal 0; - } - - .header{ - padding: $padding-default-horizontal $padding-default-horizontal 0px; - color: $black-color; - font-weight: $font-weight-light; - font-size: $font-size-h4; - - - } - .category, - .form-group > label{ - font-size: $font-size-base; - font-weight: $font-weight-normal; - color: $default-color; - margin-bottom: 0px; - - &.error{ - text-transform: none; - color: $danger-color; - } - i{ - font-size: $font-paragraph; - } - } - - .form-group > label{ - font-size: $font-size-small; - margin-bottom: 5px; - text-transform: uppercase; - } - - .title{ - margin: $none; - color: $black-color; - font-weight: $font-weight-light; - } - .avatar{ - width: 30px; - height: 30px; - overflow: hidden; - border-radius: 50%; - margin-right: 5px; - } - .description{ - font-size: $font-size-base; - color: #333; - } - .footer{ - padding: 0 $padding-default-horizontal $padding-default-vertical; - background-color: $transparent-bg; - line-height: 30px; - - .form-group label{ - margin-bottom: 0; - } - - .legend{ - padding: 5px 0; - } - - hr{ - margin-top: 5px; - margin-bottom: 5px; - } - } - .stats{ - color: #a9a9a9; - } -/* - .footer div{ - display: inline-block; - } -*/ - - .author{ - font-size: $font-size-small; - font-weight: $font-weight-bold; - text-transform: uppercase; - } - .author i{ - font-size: $font-size-base; - } - h6{ - font-size: $font-size-small; - margin: 0; - } - &.card-separator:after{ - height: 100%; - right: -15px; - top: 0; - width: 1px; - background-color: $medium-gray; - content: ""; - position: absolute; - } - - .ct-chart{ - margin: 30px 0 30px; - height: 245px; - } - - - //custom properties for tables that are inside cards - .table{ - margin-bottom: 0; - - tbody .bs-checkbox input, - thead .bs-checkbox .th-inner{ - padding-left: 15px; - } - - tbody td:last-child, - thead th:last-child{ - padding-right: 15px; - } - - tbody td.bs-checkbox:first-child{ - padding-left: 23px !important; - } - } - - .alert{ - border-radius: $border-radius-base; - position: relative; - - &.alert-with-icon{ - padding-left: 65px; - } - } - - &.card-plain{ - background-color: transparent !important; - box-shadow: none !important; - border-radius: 0 !important; - - .image{ - border-radius: 4px; - } - } -} -.card-user{ - .image{ - height: 110px; - } - .image-plain{ - height: 0; - margin-top: 110px; - } - .author{ - text-align: center; - text-transform: none; - margin-top: -70px; - } - .avatar{ - width: 124px; - height: 124px; - border: 5px solid #FFFFFF; - position: relative; - margin-bottom: 15px; - - &.border-gray{ - border-color: #EEEEEE; - } - } - .title{ - line-height: 24px; - } - .content{ - min-height: 240px; - } -} - -.card-user, -.card-price{ - .footer{ - padding: 5px 15px 10px; - } - hr{ - margin: 5px 15px; - } -} - - -.card-wizard{ - border-radius: $border-radius-extreme; - - .nav-pills{ - margin-left: -$padding-default-horizontal; - margin-right: -$padding-default-horizontal; - margin-top: 10px; - margin-bottom: 10px; - - > li{ - - > a{ - text-align: center; - border: none; - background-color: $dark-gray; - color: $white-color; - text-transform: uppercase; - - &:hover, - &:focus{ - background-color: $dark-gray; - outline: 0 !important; - } - } - - &:first-child > a, - &:last-child > a{ - border-radius: 0; - } - } - } - - .btn-finish{ - display: none; - } - - .header{ - padding-top: ($padding-default-vertical + 15); - padding-bottom: ($padding-default-vertical); - } - - .footer{ - padding-bottom: ($padding-default-vertical + 5); - } -} diff --git a/frontend/assets/sass/nomad-ui/_carousel.scss b/frontend/assets/sass/nomad-ui/_carousel.scss deleted file mode 100644 index 5518df88..00000000 --- a/frontend/assets/sass/nomad-ui/_carousel.scss +++ /dev/null @@ -1,15 +0,0 @@ -.carousel-control{ - width: 8%; -} -.carousel-control .icon-prev, .carousel-control .icon-next, .carousel-control .fa, .carousel-control .fa { - display: inline-block; - position: absolute; - top: 50%; - z-index: 5; -} -.carousel-control .fa{ - font-size: 35px; -} -.carousel-control.left, .carousel-control.right { - background-image: none; -} \ No newline at end of file diff --git a/frontend/assets/sass/nomad-ui/_checkbox-radio-switch.scss b/frontend/assets/sass/nomad-ui/_checkbox-radio-switch.scss deleted file mode 100644 index 31ec6018..00000000 --- a/frontend/assets/sass/nomad-ui/_checkbox-radio-switch.scss +++ /dev/null @@ -1,253 +0,0 @@ -/* Checkbox and radio */ -.checkbox, -.radio { - margin-bottom: 12px; - padding-left: 24px; - position: relative; - -webkit-transition: color 0.25s linear; - transition: color 0.25s linear; - font-size: 14px; - font-weight: normal; - line-height: 1.5; - color: #333333; -} -.checkbox input, -.radio input { - outline: none !important; - opacity: 0; - margin-left: -9999px; - position: absolute; -} -.checkbox .icons, -.radio .icons { - color: $medium-gray; - display: block; - height: 20px; - left: 0; - position: absolute; - top: 0; - width: 20px; - text-align: center; - line-height: 21px; - font-size: 20px; - cursor: pointer; - -webkit-transition: color 0.2s linear; - transition: color 0.2s linear; -} - - -.checkbox .icons .first-icon, -.radio .icons .first-icon, -.checkbox .icons .second-icon, -.radio .icons .second-icon { - display: inline-table; - position: absolute; - left: 0; - top: 0; - background-color: transparent; - margin: 0; - @include opacity(1); -} -.checkbox .icons .second-icon, -.radio .icons .second-icon { - @include opacity(0); -} -.checkbox:hover, -.radio:hover { - -webkit-transition: color 0.2s linear; - transition: color 0.2s linear; -} -.checkbox:hover .first-icon, -.radio:hover .first-icon { - @include opacity(0); -} -.checkbox:hover .second-icon, -.radio:hover .second-icon { - @include opacity (1); -} -.checkbox.checked .icons, -.radio.checked .icons{ - color: $info-color; -} -.checkbox.checked .first-icon, -.radio.checked .first-icon { - opacity: 0; - filter: alpha(opacity=0); -} -.checkbox.checked .second-icon, -.radio.checked .second-icon { - opacity: 1; - filter: alpha(opacity=100); - color: $info-color; - -webkit-transition: color 0.2s linear; - transition: color 0.2s linear; -} -.checkbox.disabled, -.radio.disabled { - cursor: default; - color: $medium-gray !important; -} -.checkbox.disabled .icons, -.radio.disabled .icons { - color: $medium-gray !important; -} -.checkbox.disabled .first-icon, -.radio.disabled .first-icon { - opacity: 1; - filter: alpha(opacity=100); -} -.checkbox.disabled .second-icon, -.radio.disabled .second-icon { - opacity: 0; - filter: alpha(opacity=0); -} -.checkbox.disabled.checked .icons, -.radio.disabled.checked .icons { - color: $medium-gray; -} -.checkbox.disabled.checked .first-icon, -.radio.disabled.checked .first-icon { - opacity: 0; - filter: alpha(opacity=0); -} -.checkbox.disabled.checked .second-icon, -.radio.disabled.checked .second-icon { - opacity: 1; - filter: alpha(opacity=100); - color: #D9D9D9; -} - -.checkbox label.error, -.radio label.error{ - position: absolute; - top: 15px; - left: 5px; -} - - -/* ============================================================ - * bootstrapSwitch v1.3 by Larentis Mattia @spiritualGuru - * http://www.larentis.eu/switch/ - * ============================================================ - * Licensed under the Apache License, Version 2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * ============================================================ */ -.has-switch { - border-radius: 30px; - cursor: pointer; - display: inline-block; - line-height: 1.72222; - overflow: hidden; - position: relative; - text-align: left; - width: 60px; - - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - -o-user-select: none; - user-select: none; - - /* this code is for fixing safari bug with hidden overflow for border-radius */ - -webkit-mask: url('../img/mask.png') 0 0 no-repeat; - -webkit-mask-size: 60px 28px; - mask: url('../img/mask.png') 0 0 no-repeat; -} -.has-switch.deactivate { - opacity: 0.5; - filter: alpha(opacity=50); - cursor: default !important; -} -.has-switch.deactivate label, -.has-switch.deactivate span { - cursor: default !important; -} -.has-switch > div { - position: relative; - top: 0; - width: 100px; -} -.has-switch > div.switch-animate { - -webkit-transition: left 0.25s ease-out; - transition: left 0.25s ease-out; -} -.has-switch > div.switch-off { - left: -32px; -} - -.has-switch > div.switch-on { - left: 0; -} -.has-switch > div label { - background-color: #FFFFFF; - @include line-gradient (rgba(255,255,255,1), rgba(241,241,242,1)); - - box-shadow: 0 1px 1px #FFFFFF inset, 0 1px 1px rgba(0, 0, 0, 0.25); - cursor: pointer; -} -.has-switch input[type=checkbox] { - display: none; -} -.has-switch span { -/* box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2) inset; */ - cursor: pointer; - float: left; - font-size: 11px; - font-weight: 400; - height: 28px; - line-height: 15px; - margin: 0; - padding-bottom: 6px; - padding-top: 7px; - position: relative; - text-align: center; - text-indent: -10px; - width: 50%; - z-index: 1; - -webkit-transition: 0.25s ease-out; - transition: 0.25s ease-out; -} -.has-switch span.switch-left { - background-color: $info-color; - border-left: 1px solid rgba(0, 0, 0, 0); - border-radius: 30px 0 0 30px; - color: #FFFFFF; -} -.has-switch .switch-off span.switch-left{ - background-color: $medium-gray; -} -.has-switch span.switch-right { - border-radius: 0 30px 30px 0; - background-color: $info-color; - color: #ffffff; - text-indent: -3px; -} -.has-switch .switch-off span.switch-right{ - background-color: $medium-gray; -} - -.has-switch label { - border-radius: 12px; - float: left; - height: 22px; - margin: 3px -15px; - padding: 0; - position: relative; - transition: all 0.25s ease-out 0s; - vertical-align: middle; - width: 22px; - z-index: 100; - -webkit-transition: 0.25s ease-out; - transition: 0.25s ease-out; -} -.has-switch .switch-on .fa-check:before{ - margin-left: 10px; -} -.has-switch:hover .switch-on label{ - margin: 3px -19px; - width: 26px; -} -.has-switch:hover .switch-off label{ - margin: 3px -15px; - width: 26px; -} diff --git a/frontend/assets/sass/nomad-ui/_collapse.scss b/frontend/assets/sass/nomad-ui/_collapse.scss deleted file mode 100644 index 8449bda4..00000000 --- a/frontend/assets/sass/nomad-ui/_collapse.scss +++ /dev/null @@ -1,49 +0,0 @@ -.panel { - border: 0; - border-bottom: 1px solid $medium-gray; - box-shadow: none; -} -.panel-default > .panel-heading { - background-color: $white-color; - border-color: $white-color; -} -.panel-group .panel{ - border-radius: 0; -} -.panel-title{ - font-size: $font-size-h5; -} -.panel-title a:hover, .panel-title a:focus{ - text-decoration: none; -} -.collapse-hover{ - display: block; - height: 0px; - visibility: visible; - overflow: hidden; -} -.panel-title a:hover, .panel-title a:focus{ - color: $default-states-color; -} -.panel-default > .panel-heading + .panel-collapse > .panel-body { - box-shadow: inset 0 7px 10px -7px rgba(0,0,0,0.14); -} -.panel-heading{ - padding: 0; - - .caret{ - float: right; - margin-top: 12px; - margin-right: $padding-default-horizontal; - } - - a{ - padding: $padding-default-vertical 0; - display: block; - width: 100%; - - .content-full-width &{ - padding: $padding-default-vertical $padding-default-horizontal; - } - } -} diff --git a/frontend/assets/sass/nomad-ui/_dropdown.scss b/frontend/assets/sass/nomad-ui/_dropdown.scss deleted file mode 100644 index 17b0bf7d..00000000 --- a/frontend/assets/sass/nomad-ui/_dropdown.scss +++ /dev/null @@ -1,176 +0,0 @@ -.dropdown-menu{ - margin: 0; - padding: 0; - border-radius: $border-radius-extreme; - z-index: 9000; - @include box-shadow($dropdown-shadow); - - > li > a { - padding: $padding-base-vertical $padding-base-horizontal; - color: #333333; - - img{ - margin-top: -3px; - } - } - > li > a:focus{ - outline: 0 !important; - } - - .btn-group.select &{ - min-width: 100%; - } - - > li:first-child > a{ - margin-top: 5px; - border-top-left-radius: $border-radius-small; - border-top-right-radius: $border-radius-small; - } - - > li:last-child > a{ - margin-bottom: 5px; - border-bottom-left-radius: $border-radius-small; - border-bottom-right-radius: $border-radius-small; - } - - .select & > li:first-child > a{ - border-radius: 0; - border-bottom: 0 none; - } - - > li > a:hover, - > li > a:focus, - > li.selected > a{ - background-color: $smoke-bg; - color: #333333; - opacity: 1; - text-decoration: none; - } - - > .active > a, - > .active > a:focus, - > .active > a:hover,{ - background-color: $light-blue; - color: #333333; - } - - &:before{ - border-bottom: 11px solid rgba(0, 0, 0, 0.2); - border-left: 11px solid rgba(0, 0, 0, 0); - border-right: 11px solid rgba(0, 0, 0, 0); - content: ""; - display: inline-block; - position: absolute; - left: 12px; - top: -11px; - } - &:after { - border-bottom: 11px solid #FFFFFF; - border-left: 11px solid rgba(0, 0, 0, 0); - border-right: 11px solid rgba(0, 0, 0, 0); - content: ""; - display: inline-block; - position: absolute; - left: 12px; - top: -10px; - } - - .pull-right &:before{ - left: auto; - right: 12px; - } - .pull-right &:after{ - left: auto; - right: 12px; - } - - .dropup &:before{ - border-bottom: none; - border-top: 11px solid rgba(0, 0, 0, 0.2); - border-left: 11px solid rgba(0, 0, 0, 0); - border-right: 11px solid rgba(0, 0, 0, 0); - content: ""; - display: inline-block; - position: absolute; - left: 12px; - top: auto; - bottom: -11px; - } - .dropup &:after { - border-bottom: none; - border-top: 11px solid #FFFFFF; - border-left: 11px solid rgba(0, 0, 0, 0); - border-right: 11px solid rgba(0, 0, 0, 0); - content: ""; - display: inline-block; - position: absolute; - left: 12px; - top: auto; - bottom: -10px; - } - - &.dropdown-blue > li > a:hover, - &.dropdown-blue > li > a:focus, - &.dropdown-blue > li.selected > a{ - background-color: $light-blue; - } - &.dropdown-azure > li > a:hover, - &.dropdown-azure > li > a:focus, - &.dropdown-azure > li.selected > a{ - background-color: $light-azure; - } - &.dropdown-green > li > a:hover, - &.dropdown-green > li > a:focus, - &.dropdown-green > li.selected > a{ - background-color: $light-green; - } - &.dropdown-orange > li > a:hover, - &.dropdown-orange > li > a:focus, - &.dropdown-orange > li.selected > a{ - background-color: $light-orange; - } - &.dropdown-red > li > a:hover, - &.dropdown-red > li > a:focus, - &.dropdown-red > li.selected > a{ - background-color: $light-red; - } - - & > li.disabled > a{ - background-color: transparent !important; - opacity: .5; - } -} - -.dropdown-with-icons{ - > li > a{ - padding-left: 0px; - line-height: 28px; - } - - .dropdown-menu{ - min-width: 180px; - - i{ - text-align: center; - line-height: 28px; - float: left; - - &[class^="pe-"]{ - font-size: 24px; - width: 46px; - } - &[class^="fa"]{ - font-size: 14px; - width: 38px; - } - } - } -} - -//fix bug for the select items in btn-group -.btn-group.select{ - overflow: hidden; -} -.btn-group.select.open{ - overflow: visible; -} diff --git a/frontend/assets/sass/nomad-ui/_footers.scss b/frontend/assets/sass/nomad-ui/_footers.scss deleted file mode 100644 index 65aac5cc..00000000 --- a/frontend/assets/sass/nomad-ui/_footers.scss +++ /dev/null @@ -1,155 +0,0 @@ -.footer{ - background-color: $white-color; - line-height: $line-height; - - nav > ul{ - list-style: none; - margin: 0; - padding: 0; - font-weight: normal; - - a:not(.btn){ - color: $dark-gray; - display: block; - margin-bottom: 3px; - &:hover, - &:focus{ - color: $default-states-color; - } - } - } - .social-area{ - padding: 15px 0; - h5{ - padding-bottom: 15px; - } - } - .social-area > a:not(.btn){ - color: $dark-gray; - display: inline-block; - vertical-align: top; - padding: $padding-social-a; - font-size: $font-size-large-navbar; - font-weight: normal; - line-height: $line-height; - text-align: center; - &:hover, - &:focus{ - color: $default-states-color; - } - } - .copyright{ - color: $default-states-color; - padding: 10px 15px; - margin: 10px 3px; - line-height: 31px; - font-size: $font-size-base; - } - hr{ - border-color: $medium-gray; - } - .title{ - color: $default-states-color; - } -} - -.footer-default{ - background-color: $smoke-bg; -} - -.footer:not(.footer-big){ - nav > ul{ - font-size: 16px; - li{ - margin-left: 20px; - float: left; - } - a{ - padding: 10px 0px; - margin: 15px 10px 15px 0px; - } - } -} - -.footer-black, -.footer-transparent{ - background-color: $black-bg; - color: $medium-gray; - - nav > ul{ - a{ - color: $white-color; - &:hover, - &:focus{ - color: $dark-gray; - } - } - } - .social-area > a:not(.btn){ - color: $white-color; - &:hover, - &:focus{ - color: $dark-gray; - } - } - .btn-social{ - color: $white-color; - } - hr{ - border-color: $black-hr; - } - .title{ - color: $medium-gray; - } -} - -.footer-transparent{ - background-attachment: fixed; - background-size: cover; - position: relative; - background-color: transparent; - - .container{ - z-index: 2; - position: relative; - } - - -} - -.footer-big{ - padding-top: 30px; - - hr{ - margin-bottom: 0; - margin-top: 50px; - } - .copyright{ - margin: 10px 0px 20px; - } - .social-area > *{ - margin: 0 15px; - } - - nav > ul{ - list-style: none; - margin: 0; - padding: 0; - font-weight: normal; - li{ - float: none; - } - .btn{ - margin-bottom: 5px; - } - .btn-social.btn-simple{ - padding: 0 0 4px 0; - } - } - .form-group{ - margin-top: 15px; - } - .numbers h4{ - margin: $margin-bottom; - } -} diff --git a/frontend/assets/sass/nomad-ui/_forms.scss b/frontend/assets/sass/nomad-ui/_forms.scss deleted file mode 100644 index 3a7a2078..00000000 --- a/frontend/assets/sass/nomad-ui/_forms.scss +++ /dev/null @@ -1,41 +0,0 @@ -form{ - - label{ - &.radio, - &.checkbox{ - font-size: $font-size-base; - text-transform: none; - cursor: pointer; - } - } -} - -.form-horizontal{ - .checkbox, - .radio{ - padding-top: 0; - - &:first-child, - &.checkbox-inline, - &.radio-inline{ - margin-top: 10px; - } - } -} - -star{ - color: $danger-color; - padding-left: 3px; -} - -@media (min-width: $screen-md-min){ - .form-horizontal{ - .control-label{ - padding-top: 12px !important; - } - code{ - margin-top: 8px; - display: inline-block; - } - } -} diff --git a/frontend/assets/sass/nomad-ui/_inputs.scss b/frontend/assets/sass/nomad-ui/_inputs.scss deleted file mode 100755 index fac32f2c..00000000 --- a/frontend/assets/sass/nomad-ui/_inputs.scss +++ /dev/null @@ -1,170 +0,0 @@ -.form-control::-moz-placeholder{ - @include placeholder($placeholder-gray,1); -} -.form-control:-moz-placeholder{ - @include placeholder($placeholder-gray,1); -} -.form-control::-webkit-input-placeholder{ - @include placeholder($placeholder-gray,1); -} -.form-control:-ms-input-placeholder{ - @include placeholder($placeholder-gray,1); -} - -.form-control { - background-color: $white-bg; - border: 1px solid $light-gray; - border-radius: $border-radius-base; - color: #565656; - @include input-size($padding-base-vertical, $padding-base-horizontal - 4, $height-base); - @include box-shadow(none); - - &:focus{ - background-color: $white-bg; - border: 1px solid $medium-dark-gray; - @include box-shadow(none); - outline: 0 !important; - color: #333333; - } - - .has-error &, - .has-error &:focus, - .has-success &, - .has-warning &, - .has-success &:focus, - .has-warning &:focus{ - border-color: $light-gray; - @include box-shadow(none); - } - - .has-success &:focus, - &.valid:focus{ - border-color: $success-color; - } - - .has-error &, - &.error, - .has-error &:focus{ - color: $danger-color; - border-color: $danger-color; - } - - & + .form-control-feedback{ - border-radius: $border-radius-large; - font-size: $font-size-base; - margin-top: -7px; - position: absolute; - right: 10px; - top: 50%; - vertical-align: middle; - } - - .open &{ - border-radius: $border-radius-base $border-radius-base 0 0; - border-bottom-color: transparent; - } -} -.input-sm{ - height: 30px; - padding: $padding-small-vertical $padding-small-horizontal; -} -.input-lg{ - height: 55px; - padding: $padding-large-vertical $padding-large-horizontal; -} - -.has-error{ - .form-control-feedback{ - color: $danger-color; - } -} -.has-success{ - .form-control-feedback{ - color: $success-color - } -} - -.control-label{ - .has-success &{ - color: $success-color; - } - - .has-warning &{ - color: $warning-color; - } - - .has-error &{ - color: $danger-color; - } -} - -.input-group-addon { - background-color: $white-color; - border: 1px solid $light-gray; - border-radius: $border-radius-base; - - .has-success &, - .has-error &{ - background-color: $white-color; - border: 1px solid $light-gray; - } - - .has-error &, - .has-error.input-group-focus &{ - border-color: $danger-color; - color: $danger-color; - } - - .has-success.input-group-focus &{ - border-color: $success-color; - } - .has-error .form-control:focus + &{ - border-color: $danger-color; - color: $danger-color; - } - .has-success .form-control:focus + &{ - border-color: $success-color; - color: $success-color; - } - .form-control:focus + &, - .form-control:focus ~ &{ - background-color: $white-color; - border-color: $dark-gray; - } -} - -.input-group .form-control:first-child, -.input-group-addon:first-child, -.input-group-btn:first-child > .dropdown-toggle, -.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) { - border-right: 0 none; -} -.input-group .form-control:last-child, -.input-group-addon:last-child, -.input-group-btn:last-child > .dropdown-toggle, -.input-group-btn:first-child > .btn:not(:first-child) { - border-left: 0 none; -} -.form-control[disabled], -.form-control[readonly], -fieldset[disabled] .form-control { - background-color: $smoke-bg; - color: $default-color; - cursor: not-allowed; -} - -.input-group-btn .btn{ - border-width: $border-thin; - padding: $padding-round-vertical $padding-base-horizontal; -} -.input-group-btn .btn-default:not(.btn-fill){ - border-color: $medium-gray; -} - -.input-group-btn:last-child > .btn{ - margin-left: 0; -} - -.input-group-focus .input-group-addon{ - border-color: $medium-dark-gray; -} diff --git a/frontend/assets/sass/nomad-ui/_labels.scss b/frontend/assets/sass/nomad-ui/_labels.scss deleted file mode 100644 index 353b6efa..00000000 --- a/frontend/assets/sass/nomad-ui/_labels.scss +++ /dev/null @@ -1,54 +0,0 @@ -/* Labels */ -.label{ - padding: 0.2em 0.6em 0.2em; - border: 1px solid #999999; - border-radius: 3px; - color: #999999; - background-color: #FFFFFF; - font-weight: 500; - font-size: 11px; - text-transform: uppercase; - display: inline-block; - margin-bottom: 3px; -} -.label-primary{ - border-color: #3472F7; - color: #3472F7; -} -.label-info{ - border-color: #2CA8FF; - color: #2CA8FF; -} -.label-success{ - border-color: #05AE0E; - color: #05AE0E; -} -.label-warning{ - border-color: #FF9500; - color: #FF9500; -} -.label-danger{ - border-color: #FF3B30; - color: #FF3B30; -} -.label.label-fill{ - color: #FFFFFF; -} -.label-primary.label-fill{ - background-color: #3472F7; -} -.label-info.label-fill{ - background-color: #2CA8FF; -} -.label-success.label-fill{ - background-color: #05AE0E; -} -.label-warning.label-fill{ - background-color: #FF9500; -} -.label-danger.label-fill{ - background-color: #FF3B30; -} -.label-default.label-fill{ - background-color: #999999; -} diff --git a/frontend/assets/sass/nomad-ui/_media.scss b/frontend/assets/sass/nomad-ui/_media.scss deleted file mode 100644 index f8ded151..00000000 --- a/frontend/assets/sass/nomad-ui/_media.scss +++ /dev/null @@ -1,80 +0,0 @@ -.media{ - border-bottom: 1px solid $medium-gray; - padding-bottom: 30px; - margin-top: 30px; - - .avatar{ - margin: 0 auto; - width: 64px; - height: 64px; - overflow: hidden; - border-radius: 50%; - margin-right: 15px; - border: 3px solid transparent; - - img{ - width: 100%; - } - } - .media-heading{ - margin-bottom: 10px; - margin-top: 5px; - display: inline-block; - } - .btn-simple{ - padding: 0px 5px; - } - .media{ - margin-top: 30px; - } - .media:last-child{ - border: 0; - } -} - -.media-post{ - color: #555; - border: 0; - .media-heading{ - display: block; - text-align: center; - } - .author{ - width: 15%; - } - .media-body{ - width: 85%; - float: left; - display: inline-block; - } - textarea{ - margin: $margin-bottom; - font-size: $font-paragraph; - } - .avatar{ - border-color: white; - } -} - - -.media-area{ - .media:last-child{ - border: 0; - } - .pagination-area{ - padding: 10px 0; - text-align: center; - } -} -.media-area-small{ - p{ - font-size: 14px; - } - .btn-simple{ - font-size: 14px; - } - .avatar{ - width: 58px; - height: 58px; - } -} diff --git a/frontend/assets/sass/nomad-ui/_misc.scss b/frontend/assets/sass/nomad-ui/_misc.scss deleted file mode 100755 index e0165e84..00000000 --- a/frontend/assets/sass/nomad-ui/_misc.scss +++ /dev/null @@ -1,87 +0,0 @@ -/* General overwrite */ -body, -.wrapper{ - min-height: 100vh; - position: relative; -} - -a{ - color: $color-nomad; - - &:hover, &:focus{ - color: $color-nomad-dark; - text-decoration: none; - } -} - -a:focus, a:active, -button::-moz-focus-inner, -input::-moz-focus-inner, -input[type="reset"]::-moz-focus-inner, -input[type="button"]::-moz-focus-inner, -input[type="submit"]::-moz-focus-inner, -select::-moz-focus-inner, -input[type="file"] > input[type="button"]::-moz-focus-inner{ - outline:0; -} -.ui-slider-handle:focus, -.navbar-toggle, -input:focus { - outline : 0 !important; -} - -/* Animations */ - -.animation-transition-general{ - @include transition($general-transition-time, $transition-linear); -} - -.animation-transition-fast{ - @include transition($fast-transition-time, $transition-linear); -} - -.animation-transition-ultra-fast{ - @include transition($ultra-fast-transition-time, $transition-ease-in); -} - -.form-control, -.input-group-addon, -.tagsinput, -.navbar .alert, -.panel-collapse.collapse-hover { - @include transition($general-transition-time, $transition-linear); -} - -.sidebar .nav a, -.table > tbody > tr .td-actions .btn, -.caret{ - @include transition($fast-transition-time, $transition-ease-in); -} - -.btn{ - @include transition($ultra-fast-transition-time, $transition-ease-in); -} -.fa{ - width: 18px; - text-align: center; -} -.margin-top{ - margin-top: 50px; -} - -a[data-toggle="collapse"][aria-expanded="true"] .caret, -.btn[data-toggle="collapse"][aria-expanded="true"] .caret, -a.dropdown-toggle[aria-expanded="true"] .caret{ - @include rotate-180(); -} - -legend{ - font-size: $font-size-h4; - font-weight: $font-weight-light; -} - -.full-screen-map{ - position:relative; - width:100%; - height: calc(100% - 60px); -} diff --git a/frontend/assets/sass/nomad-ui/_mixins.scss b/frontend/assets/sass/nomad-ui/_mixins.scss deleted file mode 100644 index c752a973..00000000 --- a/frontend/assets/sass/nomad-ui/_mixins.scss +++ /dev/null @@ -1,22 +0,0 @@ -//Utilities - -@import "mixins/transparency"; -@import "mixins/vendor-prefixes"; - - -//Components - -@import "mixins/buttons"; -@import "mixins/inputs"; -@import "mixins/labels"; -@import "mixins/tabs"; - -@import "mixins/navbars"; -@import "mixins/icons"; -@import "mixins/social-buttons"; - -@import "mixins/morphing-buttons"; - -@import "mixins/cards"; -@import "mixins/table-row"; -@import "mixins/chartist"; diff --git a/frontend/assets/sass/nomad-ui/_modal.scss b/frontend/assets/sass/nomad-ui/_modal.scss deleted file mode 100644 index 3e367c83..00000000 --- a/frontend/assets/sass/nomad-ui/_modal.scss +++ /dev/null @@ -1,79 +0,0 @@ -.modal-header { - border: 0 none; -} -.modal-content { - border: 0 none; - border-radius: 10px; - box-shadow: 0 0 15px rgba(0, 0, 0, 0.15), 0 0 1px 1px rgba(0, 0, 0, 0.1); -} -.modal-dialog { - padding-top: 60px; -} -.modal-footer { - border-top: 0 none; - padding: 10px 10px; -} -.modal-footer .modal-footer .btn-default.btn-simple{ - font-weight: 400; -} - -.modal.fade .modal-dialog { - transform: none; - -webkit-transform: none; - -moz-transform: none; -} -.modal.in .modal-dialog { - transform: none; - -webkit-transform: none; - -moz-transform: none; -} -.modal-small{ - .modal-dialog{ - max-width: 350px; - } -} -.modal-small{ - .divider{ - margin: 0 auto; - display: block; - width: 14px; - position: relative; - margin-top: 40px; - margin-bottom: 30px; - font-size: $font-paragraph; - } - .divider:after{ - position: absolute; - content: ""; - right: -140px; - top: 12px; - height: 1px; - width: 115px; - background-color: $light-gray; - } - .divider:before{ - position: absolute; - content: ""; - left: -140px; - top: 12px; - height: 1px; - width: 115px; - background-color: $light-gray; - } - .modal-footer{ - text-align: center; - } -} -.social-area{ - text-align: center; - - .btn-social{ - margin: 0 10px; - } -} -.modal-backdrop.in { - opacity: 0.25; -} - - - diff --git a/frontend/assets/sass/nomad-ui/_navbars.scss b/frontend/assets/sass/nomad-ui/_navbars.scss deleted file mode 100644 index 45df7edd..00000000 --- a/frontend/assets/sass/nomad-ui/_navbars.scss +++ /dev/null @@ -1,362 +0,0 @@ -.nav { - > li{ - > a:hover, - > a:focus{ - background-color: transparent; - } - } -} -.navbar{ - border: $none; - font-size: $font-size-navbar; - border-radius: 0; - - .navbar-minimize{ - float: left; - margin: 3px 15px; - } - - - .navbar-brand { - font-weight: $font-weight-normal; - margin: $navbar-margin-brand; - padding: $navbar-padding-brand; - font-size: $font-size-large-navbar; - } - .navbar-nav{ - > li > a { - padding: $navbar-padding-a; - margin: $navbar-margin-a; - position: relative; - - } - > li > a.btn{ - margin: $navbar-margin-a-btn; - padding: $padding-base-vertical $padding-base-horizontal; - } - > li > a.btn-round{ - margin: $navbar-margin-a-btn-round; - } - > li > a [class^="fa"]{ - font-size: $font-size-large + 1; - position: relative; - line-height: 16px; - top: 1px; - } - - p{ - display: inline-block; - padding-left: 10px; - margin-bottom: 0; - } - - .notification{ - position: absolute; - background-color: #FB404B; - text-align: center; - border-radius: 10px; - min-width: 18px; - padding: 0 5px; - height: 18px; - font-size: 12px; - color: #FFFFFF; - font-weight: bold; - line-height: 18px; - top: 2px; - left: 7px; - } - } - .btn{ - margin: $navbar-margin-btn; - font-size: $font-size-base; - } - .btn-simple{ - font-size: $font-size-medium; - } - .caret{ - // @include center-item(); - } - - &.fixed{ - width: calc(100% - $sidebar-width); - right: 0; - left: auto; - border-radius: 0; - } - - &.navbar-absolute{ - position: absolute; - width: 100%; - z-index: 1030; - } - -} - -.navbar-fixed{ - position: fixed; - width: 100%; - right: 0; - z-index: 1031; - - & ~ .main-panel{ - > .content{ - padding-top: 95px; - min-height: calc(100% - 71px); - } - } - -} - -.navbar-nav > li > .dropdown-menu{ - border-radius: $border-radius-extreme; - margin-top: -5px; -} - -.navbar-transparent, [class*="navbar-ct"]{ - .navbar-brand{ - color: $white-color; - @include opacity(.9); - - &:focus, - &:hover{ - background-color: transparent; - @include opacity(1); - } - } - - .navbar-nav{ - > li > a:not(.btn){ - color: $white-color; - border-color: $white-color; - @include opacity(0.8); - } - > .active > a:not(.btn), - > .active > a:hover:not(.btn), - > .active > a:focus:not(.btn), - > li > a:hover:not(.btn), - > li > a:focus:not(.btn){ - background-color: transparent; - border-radius: 3px; - color: $white-color; - @include opacity(1); - } - .nav > li > a.btn:hover{ - background-color: transparent; - } - - > .dropdown > a .caret, - > .dropdown > a:hover .caret, - > .dropdown > a:focus .caret{ - border-bottom-color: $white-color; - border-top-color: $white-color; - } - - > .open > a, - > .open > a:hover, - > .open > a:focus { - background-color: transparent; - color: $white-color; - @include opacity(1); - } - } - - .btn-default{ - color: $white-color; - border-color: $white-color; - } - .btn-default.btn-fill{ - color: $dark-gray; - background-color: $white-color; - @include opacity(.9); - } - .btn-default.btn-fill:hover, - .btn-default.btn-fill:focus, - .btn-default.btn-fill:active, - .btn-default.btn-fill.active, - .open .dropdown-toggle.btn-fill.btn-default{ - border-color: $white-color; - @include opacity(1); - } - -} -.navbar-transparent{ - .dropdown-menu .divider{ - background-color: rgba($white-color,.2); - } -} - -.nav-open .nav .caret{ - border-bottom-color: $white-color; - border-top-color: $white-color; -} - -.navbar-default { - background-color: $white-navbar; - border-bottom: 1px solid rgba(0, 0, 0, 0.1); - - .navbar-nav{ - > li > a:not(.btn){ - color: $dark-gray; - } - - > .active > a, - > .active > a:not(.btn):hover, - > .active > a:not(.btn):focus, - > li > a:not(.btn):hover, - > li > a:not(.btn):focus { - background-color: transparent; - border-radius: 3px; - color: $info-color; - @include opacity(1); - } - - > .dropdown > a:hover .caret, - > .dropdown > a:focus .caret { - border-bottom-color: $info-color; - border-top-color: $info-color; - - } - - > .open > a, - > .open > a:hover, - > .open > a:focus{ - background-color: transparent; - color: $info-color; - } - - .navbar-toggle:hover,.navbar-toggle:focus { - background-color: transparent; - } - - } - - &:not(.navbar-transparent) .btn-default:hover{ - color: $info-color; - border-color: $info-color; - } - &:not(.navbar-transparent) .btn-neutral, - &:not(.navbar-transparent) .btn-neutral:hover, - &:not(.navbar-transparent) .btn-neutral:active{ - color: $dark-gray; - } -} - -/* Navbar with icons */ - -.navbar-icons{ - &.navbar .navbar-brand{ - margin-top: 12px; - margin-bottom: 12px; - } - .navbar-nav{ - > li > a{ - text-align: center; - padding: $navbar-padding-a-icons; - margin: $navbar-margin-a-icons; - } - - [class^="pe"] { - font-size: 30px; - position: relative; - } - p { - margin: 3px 0 0; - } - } -} - -.navbar-form{ - @include box-shadow(none); - .form-control{ - - @include input-size($padding-base-vertical, $padding-base-horizontal - 10, $height-base); - - border-radius: 0; - border: 0; - font-size: $font-size-navbar; - line-height: $line-height-general; - color: $light-gray; - } - .navbar-transparent & .form-control, - [class*="navbar-ct"] & .form-control, - .navbar-transparent & .input-group-addon, - [class*="navbar-ct"] & .input-group-addon{ - color: $white-color; - border: $none; - background-color: rgba(255,255,255,.13); - } - - [class*="navbar-ct"] & .form-control:focus, - [class*="navbar-ct"] & .input-group-focus .input-group-addon{ - background-color: rgba(255,255,255,.23); - color: $white-color; - } - - [class*="navbar-ct"] &{ - .form-control:-moz-placeholder{ - @include placeholder($white-color,1); - } - .form-control:-webkit-input-placeholder{ - @include placeholder($white-color,1); - } - .form-control:-ms-input-placeholder{ - @include placeholder($white-color,1); - } - } - - - .input-group-addon{ - @include light-form(); - color: $light-gray; - font-size: $font-size-navbar; - padding: 0 7px; - border-radius: $border-radius-base 0 0 $border-radius-base; - } - - & .input-group-focus .input-group-addon, - & .form-control:focus{ - color: $dark-gray; - } - -} - -.navbar-ct-blue{ - @include navbar-color($blue-navbar); -} -.navbar-ct-azure{ - @include navbar-color($azure-navbar); -} -.navbar-ct-green{ - @include navbar-color($green-navbar); -} -.navbar-ct-orange{ - @include navbar-color($orange-navbar); -} -.navbar-ct-red{ - @include navbar-color($red-navbar); -} - -.navbar-transparent{ - padding-top: 15px; - background-color: transparent; - border-bottom: 1px solid transparent; -} - -.navbar-toggle{ - margin-top: 19px; - margin-bottom: 19px; - border: $none; - - .icon-bar { - background-color: $white-color; - } - .navbar-collapse, - .navbar-form { - border-color: transparent; - } - - &.navbar-default .navbar-toggle:hover, - &.navbar-default .navbar-toggle:focus { - background-color: transparent; - } -} diff --git a/frontend/assets/sass/nomad-ui/_pages.scss b/frontend/assets/sass/nomad-ui/_pages.scss deleted file mode 100644 index db4aba3f..00000000 --- a/frontend/assets/sass/nomad-ui/_pages.scss +++ /dev/null @@ -1,215 +0,0 @@ -.wrapper{ - position: relative; - top: 0; - height: 100vh; - - &:after{ - display: table; - clear: both; - content: " "; - } - - &.wrapper-full-page{ - height: auto; - min-height: 100vh; - } -} - -.full-page{ - - &:after, - &:before{ - display: block; - content: ""; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - z-index: 2; - } - - &:before{ - opacity: .33; - background: #000000; - } - - &:after{ - @include line-gradient($black-color-top, rgba($black-color-bottom,.4)); - z-index: 3; - opacity: 1; - } - - > .content, - > .footer{ - position: relative; - z-index: 4; - } - - > .content{ - min-height: calc(100vh - 70px); - } - - .full-page-background{ - position: absolute; - z-index: 1; - height: 100%; - width: 100%; - display: block; - top: 0; - left: 0; - background-size: cover; - background-position: center center; - - } - - &[data-image]:after, - &.has-image:after{ - opacity: .9; - } - - &[data-color="blue"]:after{ - @include line-gradient($color-blue, rgba($blue-color-bottom,.6)); - } - &[data-color="azure"]:after{ - @include line-gradient($color-azure, rgba($azure-color-bottom,.6)); - } - &[data-color="green"]:after{ - @include line-gradient($color-green, rgba($green-color-bottom,.6)); - } - &[data-color="orange"]:after{ - @include line-gradient($color-orange, rgba($orange-color-bottom,.6)); - } - &[data-color="red"]:after{ - @include line-gradient($color-red, rgba($red-color-bottom,.6)); - } - &[data-color="purple"]:after{ - @include line-gradient($color-purple, rgba($purple-color-bottom,.6)); - } - - .footer nav > ul a:not(.btn), - .footer, - .footer .copyright a{ - color: $white-color; - font-size: $font-size-base; - } - -} - -.login-page, -.lock-page{ - > .content{ - padding-top: 22vh; - } -} - -.login-page{ - .card{ - box-shadow: 0 25px 30px -13px rgba(40, 40, 40, 0.4); - border-radius: $border-radius-extreme; - padding-top: $padding-default-horizontal * 2; - padding-bottom: $padding-default-horizontal * 2; - - @include transform-translate-y(0); - @extend .animation-transition-general; - - &.card-hidden{ - opacity: 0; - @include transform-translate-y(-60px); - } - - .header{ - padding-bottom: $padding-default-horizontal * 2; - } - - .btn-wd{ - min-width: 180px; - } - } -} - -.lock-page{ - - .user-profile{ - text-align: center; - width: 240px; - margin: 30px auto 0; - color: #FFFFFF; - position: absolute; - left: 50%; - margin-left: -120px; - display: block; - - &.with-animation{ - @include transition(300ms, $transition-ease-in); - } - - .author{ - border-radius: 50%; - width: 100px; - height: 100px; - border: 4px solid rgba($white-color,.3); - overflow: hidden; - margin: 0 auto; - @include transition(300ms, $transition-linear); - - img{ - width: 100%; - } - } - - h4{ - margin-top: $margin-base; - margin-bottom: ($margin-base * 2); - } - - } - -} - -.register-page{ - - .header-text{ - color: #FFFFFF; - text-align: center; - padding: ($padding-default-horizontal * 3) 0 ($padding-default-horizontal * 2); - - h4{ - margin-top: 10px; - } - - hr{ - opacity: .3; - margin-top: ($margin-base * 2); - } - } - - .media{ - color: $white-color; - margin-bottom: ($margin-base * 3); - - .icon{ - float: left; - margin-right: 5px; - } - - i{ - font-size: $font-size-h2; - } - - h4{ - margin: 0 0 5px 0; - } - } - - .form-group{ - margin-bottom: ($margin-base + 10px); - } - - .card{ - .content{ - padding-top: 0; - padding-bottom: 0; - } - } -} diff --git a/frontend/assets/sass/nomad-ui/_progress-bars.scss b/frontend/assets/sass/nomad-ui/_progress-bars.scss deleted file mode 100644 index 00e482bc..00000000 --- a/frontend/assets/sass/nomad-ui/_progress-bars.scss +++ /dev/null @@ -1,26 +0,0 @@ -.progress { - background-color: #E5E5E5; - border-radius: 3px; - box-shadow: none; - height: 4px; -} -.progress-thin{ - height: 2px; -} - -.progress-bar, -.progress-bar-primary{ - background-color: $primary-color; -} -.progress-bar-info{ - background-color: $info-color; -} -.progress-bar-success{ - background-color: $success-color; -} -.progress-bar-warning{ - background-color: $warning-color; -} -.progress-bar-danger{ - background-color: $danger-color; -} diff --git a/frontend/assets/sass/nomad-ui/_responsive.scss b/frontend/assets/sass/nomad-ui/_responsive.scss deleted file mode 100644 index 38e421af..00000000 --- a/frontend/assets/sass/nomad-ui/_responsive.scss +++ /dev/null @@ -1,688 +0,0 @@ -@media (min-width: $screen-lg-min) { - .tab-content { - padding-top: 15px !important; - } -} - -@media (min-width: $screen-md-min){ - .navbar-form { - margin: 12px 0; - padding-left: 10px; - padding-right: 10px; - } - - .dropdown-menu{ - .navbar-nav > li > &, - .dropdown &, - .dropup &, - &.bootstrap-datetimepicker-widget, - .bootstrap-table &{ - @include transition($fast-transition-time, $transition-linear); - margin-top: -20px; - visibility: hidden; - display: block; - @include opacity(0); - } - - .navbar-nav > li.open > &, - .dropdown.open &, - .dropup.open &, - .bootstrap-table .open &{ - @include opacity(1); - visibility: visible; - margin-top: 0px; - } - - &.bootstrap-datetimepicker-widget.open{ - @include opacity(1); - visibility: visible; - margin-top: 5px; - } - - .dropup &{ - margin-top: auto; - margin-bottom: -20px; - } - .dropup.open &{ - margin-top: auto; - margin-bottom: 5px; - } - } - - .navbar-nav > li > .dropdown-menu:before{ - border-bottom: 11px solid rgba(0, 0, 0, 0.2); - border-left: 11px solid rgba(0, 0, 0, 0); - border-right: 11px solid rgba(0, 0, 0, 0); - content: ""; - display: inline-block; - position: absolute; - left: 12px; - top: -11px; - } - .navbar-nav > li > .dropdown-menu:after { - border-bottom: 11px solid #FFFFFF; - border-left: 11px solid rgba(0, 0, 0, 0); - border-right: 11px solid rgba(0, 0, 0, 0); - content: ""; - display: inline-block; - position: absolute; - left: 12px; - top: -10px; - } - - .navbar-nav.navbar-right > li > .dropdown-menu:before{ - left: auto; - right: 12px; - } - - .navbar-nav.navbar-right > li > .dropdown-menu:after{ - left: auto; - right: 12px; - } - - .footer:not(.footer-big){ - nav > ul{ - li:first-child{ - margin-left: 0; - } - } - } - - body > .navbar-collapse.collapse{ - display: none !important; - } - - .card{ - form{ - [class*="col-"]{ - padding: 0 6px; - } - [class*="col-"]:first-child{ - padding-left: 15px; - } - [class*="col-"]:last-child{ - padding-right: 15px; - } - } - } - - .table-full-width{ - margin-left: -15px; - margin-right: -15px; - } - - .table-responsive{ - overflow: visible; - } - - .sidebar{ - .navbar-form{ - display: none !important; - } - .nav-mobile-menu{ - display: none; - } - } - - - .navbar-fixed{ - width: calc(100% - 260px); - } - -} - -/* Changes for small display */ - -@media (max-width: $screen-md){ - - .main-panel, - .wrapper-full-page{ - @include transform-translate-x(0px); - @include transition (0.33s, cubic-bezier(0.685, 0.0473, 0.346, 1)); - left: 0; - - width: 100%; - - > .content{ - padding: 15px 0px; - } - - .card{ - .header { - padding-bottom: 15px; - } - - margin-bottom: 15px; - } - } - - .tab-content { - padding-right: 0 !important; - } - - .navbar-transparent{ - padding-top: 15px; - } - - .dl-horizontal dt { - float: left; - width: 160px; - overflow: hidden; - clear: left; - text-align: right; - text-overflow: ellipsis; - white-space: nowrap; - } - .dl-horizontal dd { - margin-left: 180px; - } - body { - position: relative; - } - - .wrapper{ - background-color: white; - - &.wrapper-full-page{ - height: auto; - } - } - - .card .content { - padding-left: 0; - padding-right: 0; - } - - .card .content.table-responsive { - padding: 0px; - } - .container-fluid { - padding-left: 0px; - padding-right: 0px; - } - .perfect-scrollbar-off .main-panel { - overflow-x: hidden; - } - .navbar > div{ - left: 0; - width: 100%; - @include transition (0.33s, cubic-bezier(0.685, 0.0473, 0.346, 1)); - position: relative; - } - .navbar .navbar-collapse.collapse, - .navbar .navbar-collapse.collapse.in, - .navbar .navbar-collapse.collapsing{ - display: none !important; - } - - .navbar-nav > li{ - float: none; - position: relative; - display: block; - } - - .sidebar, - .bootstrap-navbar { - position: fixed; - display: block; - top: 0; - height: 100%; - width: 260px; - right: 0; - left: auto; - z-index: 1032; - visibility: visible; - overflow-y: visible; - padding: 0; - - @include transform-translate-x(260px); - @include transition (0.33s, cubic-bezier(0.685, 0.0473, 0.346, 1)); - - .user{ - .photo{ - width: 50px; - height: 50px; - border-width: 2px; - } - } - - .nav{ - i{ - font-size: $font-size-h4; - } - > li > a{ - padding-bottom: 5px; - padding-top: 5px; - color: #FFFFFF !important; - - &.dropdown-toggle{ - background: transparent; - } - } - } - - .navbar-form{ - float: none !important; - margin: $margin-base 0 0 0; - - .input-group{ - width: 100%; - - .form-control{ - background: rgba(255,255,255,.13); - border-radius: 0 $border-radius-base $border-radius-base 0; - padding-left: 0; - padding-right: 0; - color: $white-color; - - &:focus{ - background: rgba(255,255,255,.23); - } - } - - } - - .input-group-addon, - .input-group-focus .input-group-addon{ - color: #FFFFFF; - padding: 0 20px; - background: rgba(255,255,255,.13); - border-radius: $border-radius-base 0 0 $border-radius-base; - } - - .input-group-focus .input-group-addon{ - background: rgba(255,255,255,.23); - } - } - - .nav-mobile-menu{ - border-bottom: 1px solid rgba($white-color, 0.20); - margin-bottom: $margin-base; - padding-bottom: $margin-base; - padding-top: 5px; - - i{ - font-size: 18px; - } - - .notification{ - float: left; - line-height: 30px; - margin-right: 8px; - font-weight: 600; - } - - .open .dropdown-menu{ - position: static; - float: none; - width: auto; - margin-top: 0; - background-color: transparent; - border: 0; - -webkit-box-shadow: none; - box-shadow: none; - } - - .dropdown-menu{ - li{ - a{ - padding-left: 60px; - } - } - } - - .dropdown-with-icons{ - li{ - a{ - padding-left: 15px; - } - } - } - } - - .dropdown-with-icons{ - > li > a{ - padding-left: $padding-default-horizontal; - padding-top: 2px; - padding-bottom: 2px; - } - - .dropdown-menu i[class^="pe-"]{ - width: 30px; - } - } - - - .dropdown-menu:after, - .dropdown-menu:before{ - display: none; - } - - } - - .bootstrap-navbar{ - .nav{ - position: relative; - z-index: 4; - border-top: none; - - >li{ - > a{ - color: #FFFFFF; - margin: 5px 15px; - opacity: .86; - border-radius: $border-radius-base; - line-height: 30px; - font-size: 12px; - font-weight: 600; - text-transform: uppercase; - } - - &:hover > a{ - background: rgba(255,255,255,0.13); - opacity: 1; - } - - &.active > a{ - color: #FFFFFF; - opacity: 1; - background: rgba(255,255,255,0.23); - - } - } - - p { - font-size: 12px; - font-weight: 600; - line-height: 30px; - margin: 0; - text-transform: uppercase; - display: inline-block; - } - - i { - float: left; - font-size: 28px; - line-height: 30px; - margin-right: 15px; - text-align: center; - width: 30px; - } - } - - - } - - .nav-open{ - .main-panel, - .wrapper-full-page{ - left: 0; - @include transform-translate-x(-260px); - } - - .navbar-fixed > div{ - @include transform-translate-x(-260px); - } - - .sidebar, - .bootstrap-navbar{ - @include transform-translate-x(0px); - } - - .navbar-default .navbar-toggle .icon-bar{ - background-color: #222222; - } - - } - - .navbar-minimize{ - display: none; - } - - - .navbar-toggle .icon-bar { - display: block; - position: relative; - background: #fff; - width: 24px; - height: 2px; - border-radius: 1px; - margin: 0 auto; - } - - - @include topbar-x-rotation(); - @include topbar-back-rotation(); - @include bottombar-x-rotation(); - @include bottombar-back-rotation(); - - .navbar-header { - padding-left: 15px - } - .navbar-header .navbar-toggle { - margin: 10px 15px 10px 0; - width: 40px; - height: 40px; - } - .navbar-toggle .icon-bar{ - outline: 1px solid transparent; - } - - .navbar-toggle .icon-bar:nth-child(2){ - top: 0px; - @include bar-animation($topbar-back); - } - .navbar-toggle .icon-bar:nth-child(3){ - opacity: 1; - } - .navbar-toggle .icon-bar:nth-child(4){ - bottom: 0px; - @include bar-animation($bottombar-back); - } - .toggled .icon-bar:nth-child(2){ - top: 6px; - @include bar-animation($topbar-x); - } - - .toggled .icon-bar:nth-child(3){ - opacity: 0; - } - .toggled .icon-bar:nth-child(4){ - bottom: 6px; - @include bar-animation($bottombar-x); - } - - @-webkit-keyframes fadeIn { - 0% {opacity: 0;} - 100% {opacity: 1;} - } - @-moz-keyframes fadeIn { - 0% {opacity: 0;} - 100% {opacity: 1;} - } - @keyframes fadeIn { - 0% {opacity: 0;} - 100% {opacity: 1;} - } - - .dropdown-menu .divider{ - background-color: rgba(229, 229, 229, 0.15); - } - - .navbar-nav { - margin: 1px 0; - - .open .dropdown-menu > li { - & > a{ - padding: 15px 15px 5px 50px; - } - - &:first-child > a{ - padding: 5px 15px 5px 50px; - } - - &:last-child > a { - padding: 15px 15px 25px 50px; - } - } - } - - - [class*="navbar-"] .navbar-nav { - & > li > a, - > li > a:hover, - > li > a:focus, - .active > a, - .active > a:hover, - .active > a:focus, - .open .dropdown-menu > li > a, - .open .dropdown-menu > li > a:hover, - .open .dropdown-menu > li > a:focus, - .navbar-nav .open .dropdown-menu > li > a:active { - color: white; - } - - & > li > a, - > li > a:hover, - > li > a:focus, - .open .dropdown-menu > li > a, - .open .dropdown-menu > li > a:hover, - .open .dropdown-menu > li > a:focus{ - opacity: .7; - background: transparent; - } - - &.navbar-nav .open .dropdown-menu > li > a:active { - opacity: 1; - } - - & .dropdown > a{ - &:hover .caret { - border-bottom-color: #777; - border-top-color: #777; - } - &:active .caret { - border-bottom-color: white; - border-top-color: white; - } - } - - } - - .dropdown-menu { - display: none; - } - .navbar-fixed-top { - -webkit-backface-visibility: hidden; - } - - .close-layer{ - height: 100%; - width: 100%; - position: absolute; - opacity: 0; - top: 0; - left: auto; - - content: ""; - z-index: 9999; - overflow-x: hidden; - background-color: rgba(0,0,0,.35); - - @include transition($slow-transition-time, $transition-ease-in); - - &.visible{ - opacity: 1; - } - } - - .social-line .btn{ - margin: $margin-bottom; - } - .subscribe-line .form-control{ - margin: $margin-bottom; - } - .social-line.pull-right{ - float: none; - } - .footer nav.pull-left{ - float: none !important; - } - .footer:not(.footer-big) nav > ul li{ - float: none; - } - .social-area.pull-right{ - float: none !important; - } - .form-control + .form-control-feedback{ - margin-top: -8px; - } - .navbar-toggle:hover,.navbar-toggle:focus { - background-color: transparent !important; - } - .btn.dropdown-toggle{ - margin-bottom: 0; - } - .media-post .author{ - width: 20%; - float: none !important; - display: block; - margin: 0 auto 10px; - } - .media-post .media-body{ - width: 100%; - } - - .navbar-collapse.collapse{ - height: 100% !important; - } - .navbar-collapse.collapse.in { - display: block; - } - .navbar-header .collapse, .navbar-toggle { - display:block !important; - } - .navbar-header { - float:none; - } - .navbar-nav .open .dropdown-menu { - position: static; - float: none; - width: auto; - margin-top: 0; - background-color: transparent; - border: 0; - -webkit-box-shadow: none; - box-shadow: none; - } - .navbar-collapse{ - .nav p{ - font-size: $font-size-base; - margin: 0; - } - - [class^="pe-7s-"]{ - float: left; - font-size: 20px; - margin-right: 10px; - } - } - - .table-responsive { - border: 0px; - width: 100%; - margin-bottom: 15px; - overflow-x: scroll; - overflow-y: hidden; - -ms-overflow-style: -ms-autohiding-scrollbar; - -webkit-overflow-scrolling: touch; - } - - .sidebar .sidebar-wrapper{ - padding-bottom: 60px; - } - - .navbar-minimize{ - display: none; - } -} diff --git a/frontend/assets/sass/nomad-ui/_sidebar-and-main-panel.scss b/frontend/assets/sass/nomad-ui/_sidebar-and-main-panel.scss deleted file mode 100755 index 1f0c783f..00000000 --- a/frontend/assets/sass/nomad-ui/_sidebar-and-main-panel.scss +++ /dev/null @@ -1,575 +0,0 @@ -.sidebar{ - position: absolute; - top: 0; - bottom: 0; - left: 0; - width: 260px; - display: block; - z-index: 1; - color: #fff; - font-weight: 200; - - .sidebar-wrapper { - position: relative; - z-index: 4; - width: 260px; - height: calc(100vh - 64px); - - > .nav{ - margin-top: 20px; - } - - > .user ~ .nav{ - margin-top: 0; - } - - .dropdown .dropdown-backdrop{ - display: none !important; - } - - } - - .sidebar-background{ - background-image: url('../img/nomad.jpg'); - position: absolute; - z-index: 1; - height: 100%; - width: 100%; - display: block; - top: 0; - left: 0; - background-size: cover; - background-position: center center; - background-color: $color-nomad; - } - - .nav{ - - li{ - > a{ - margin: 5px 15px 0px; - border-radius: $border-radius-base; - color: #FFFFFF; - opacity: .86; - } - - &:hover > a{ - background: rgba(255,255,255,0.13); - opacity: 1; - color: #FFFFFF; - } - - &.active > a{ - color: #FFFFFF; - opacity: 1; - background: rgba(255,255,255,0.23); - - } - } - - [data-toggle="collapse"] ~ div > ul > li > a{ - padding-left: 60px; - } - - p{ - margin: 0; - line-height: 30px; - font-size: 12px; - font-weight: 600; - text-transform: uppercase; - white-space: nowrap; - position: relative; - @extend .animation-transition-general; - - .caret{ - top: 12px; - position: absolute; - right: 0; - } - } - - i{ - font-size: 28px; - float: left; - margin-right: 15px; - line-height: 30px; - width: 30px; - text-align: center; - } - } - - .logo-mini{ - display: none; - } - -} - -.sidebar, -.bootstrap-navbar{ - .logo{ - padding: $padding-default-vertical $padding-default-horizontal; - position: relative; - z-index: 4; - - p{ - float: left; - font-size: 20px; - margin: 10px 10px; - color: $white-color; - line-height: 20px; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - } - - .logo-text{ - text-transform: uppercase; - padding: 7px $padding-zero; - display: block; - font-size: $font-size-large; - color: $white-color; - font-weight: $font-weight-normal; - line-height: 30px; - text-align: center; - white-space: nowrap; - overflow: hidden; - } - - .logo-image{ - float: left; - height: 40px; - width: 40px; - margin: 0 10px; - } - - .logo-round{ - border-radius: 50%; - display: block; - overflow: hidden; - - img{ - width: 100%; - } - } - - &:before{ - content: ""; - position: absolute; - bottom: -1px; - right: 10%; - width: 80%; - height: 1px; - background-color: rgba($white-color, 0.3); - } - - } - - .user{ - border-bottom: 1px solid rgba($white-color, 0.20); - padding-bottom: 20px; - margin-top: 20px; - - .photo{ - width: 80px; - height: 80px; - overflow: hidden; - border-radius: 50%; - border: 4px solid rgba($white-color, .3); - margin: 0 auto; - @extend .animation-transition-general; - - img{ - width: 100%; - } - } - - a{ - text-align: center; - color: $white-color; - padding: $padding-base-vertical $padding-large-vertical; - text-align: center; - display: block; - @extend .animation-transition-general; - } - } - - &:after, - &:before{ - display: block; - content: ""; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - z-index: 2; - } - - &:before{ - opacity: .33; - background: #000000; - } - - &:after{ - background: $color-nomad; - z-index: 3; - opacity: 0.8; - } - - &[data-image]:after, - &.has-image:after{ - opacity: .95; - } - - // colors for the sidebar with an image - &[data-color="blue"]:after{ - @include line-gradient($color-blue, rgba($blue-color-bottom,.7)); - } - &[data-color="azure"]:after{ - @include line-gradient($color-azure, rgba($azure-color-bottom,.7)); - } - &[data-color="green"]:after{ - @include line-gradient($color-green, rgba($green-color-bottom,.7)); - } - &[data-color="orange"]:after{ - @include line-gradient($color-orange, rgba($orange-color-bottom,.7)); - } - &[data-color="red"]:after{ - @include line-gradient($color-red, rgba($red-color-bottom,.7)); - } - &[data-color="purple"]:after{ - @include line-gradient($color-purple, rgba($purple-color-bottom,.7)); - } -} - - -.main-panel{ - background: $smoke-bg; - position: relative; - // z-index: 2; fix for Modals inside .main-panel - float: right; - width: $sidebar-width; - min-height: 100%; - - > .content{ - padding: 30px 15px; - min-height: calc(100vh - 136px); - } - - > .content-no-padding{ - padding: 0; - } - - > .footer{ - border-top: 1px solid #e7e7e7; - } - - .navbar{ - margin-bottom: 0; - } -} - -.sidebar, -.main-panel, -.sidebar-wrapper, -.navbar-fixed{ - -webkit-transition-property: top,bottom,width; - transition-property: top,bottom, width; - -webkit-transition-duration: .2s,.2s, .35s; - transition-duration: .2s,.2s, .35s; - -webkit-transition-timing-function: linear,linear,ease; - transition-timing-function: linear,linear,ease; - -webkit-overflow-scrolling: touch; -} - -.sidebar, -.main-panel{ - max-height: 100%; - height: 100%; -} - -// windows os settings for perfect scrollbar off -.sidebar .sidebar-wrapper, -.main-panel{ - .perfect-scrollbar-on &, - &{ - overflow: hidden; - } -} - -// regular settings for perfect scrollbar off -.perfect-scrollbar-off{ - .sidebar .sidebar-wrapper, - .main-panel{ - overflow: auto; - } -} - -.visible-on-sidebar-regular{ - display: inline-block !important; -} -.visible-on-sidebar-mini{ - display: none !important; -} - -@media (min-width: $screen-md) { - .hover-collapse{ - display: block; - position: absolute; - top: 0; - left: 81px; - background-color: $white-color; - border: 1px solid rgba(0,0,0,.15); - border: 1px solid #ccc; - border-radius: $border-radius-extreme; - padding: 0px; - - @include box-shadow($dropdown-shadow); - - } - - .sidebar-mini{ - .visible-on-sidebar-regular{ - display: none !important; - } - .visible-on-sidebar-mini{ - display: inline-block !important; - } - .sidebar{ - width: 80px; - display: block; - font-weight: 200; - z-index: 3; - - .sidebar-wrapper{ - overflow: inherit; - width: 80px; - box-shadow: none; - } - - .logo{ - display: none; - } - - .logo-mini{ - padding: 10px 0px; - display: block; - margin: 0px; - position: relative; - z-index: 4; - - &:before{ - content: ""; - position: absolute; - bottom: -1px; - right: 10%; - width: 80%; - height: 1px; - background-color: rgba($white-color, 0.3); - } - } - - .sidebar-wrapper > .nav{ - margin-top: 20px; - - li{ - - // a{ - // margin: 5px 10px; - // } - - &:hover, - &:focus{ - .collapse{ - @extend .hover-collapse; - } - } - > a{ - margin: 5px 10px; - - &:before, - &:after{ - display:none; - } - } - } - p{ - display: none; - } - - i{ - float: none; - } - - [data-toggle="collapse"] ~ div > ul > li > a { - color: $black-color; - padding: 8px 16px; - margin: 0; - border-radius: 0; - } - - [data-toggle="collapse"] ~ div > ul > li:last-child > a{ - margin-bottom: 5px; - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; - } - - [data-toggle="collapse"] ~ div > ul > li:first-child > a{ - margin-top: 5px; - border-top-left-radius: 3px; - border-top-right-radius: 3px; - } - - } - - .info{ - - > a{ - height: 0; - padding: 0; - opacity: 0; - } - - .collapse .nav{ - li{ - >a{ - margin: 0; - border-radius: 0; - - - } - } - } - - [data-toggle="collapse"] ~ div > ul > li:last-child > a{ - margin-bottom: 5px; - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; - } - - [data-toggle="collapse"] ~ div > ul > li:first-child > a{ - margin-top: 5px; - border-top-left-radius: 3px; - border-top-right-radius: 3px; - } - } - - .user{ - position: relative; - // margin-top: 20px; - // padding: $padding-zero; - // padding-bottom: 20px; - - .nav{ - - a{ - color: $black-color; - } - } - - .photo{ - width: 50px; - height: 50px; - border-width: 2px; - } - - &:hover{ - - .collapse{ - @extend .hover-collapse; - } - } - } - - .collapse .nav{ - width: 160px; - height: auto; - position: relative; - - li{ - & > a:hover, - & > a:focus{ - - background-color: $smoke-bg; - opacity: 1; - text-decoration: none; - } - } - &:after{ - border-right: 11px solid #fff; - border-top: 11px solid rgba(0, 0, 0, 0); - border-bottom: 11px solid rgba(0, 0, 0, 0); - position: absolute; - content: ""; - display: inline-block; - left:-10px; - top:8px; - } - - - li.active{ - > a{ - background-color: $smoke-bg; - opacity: 1; - text-decoration: none; - } - } - - &:before{ - border-right: 11px solid #ccc; - border-top: 11px solid rgba(0, 0, 0, 0); - border-bottom: 11px solid rgba(0, 0, 0, 0); - position: absolute; - content: ""; - display: inline-block; - left:-11px; - top:8px; - } - &:after{ - border-right: 11px solid #fff; - border-top: 11px solid rgba(0, 0, 0, 0); - border-bottom: 11px solid rgba(0, 0, 0, 0); - position: absolute; - content: ""; - display: inline-block; - left:-10px; - top:8px; - } - - } - - } - - .main-panel{ - width: calc(100% - 80px); - margin-left: 80px; - } - - .wrapper{ - height: auto; - } - - .sidebar, - .main-panel{ - overflow: visible; - max-height: none; - height: auto; - } - - .navbar-fixed{ - width: calc(100% - 80px); - } - } -} - -@media print{ - .sidebar{ - display: none !important; - } - .main-panel{ - width: 100% !important; - max-width: none !important; - max-height: none !important; - } - .wrapper{ - height: auto !important; - } -} diff --git a/frontend/assets/sass/nomad-ui/_sliders.scss b/frontend/assets/sass/nomad-ui/_sliders.scss deleted file mode 100644 index 1563e8ad..00000000 --- a/frontend/assets/sass/nomad-ui/_sliders.scss +++ /dev/null @@ -1,219 +0,0 @@ - -/*! - * jQuery UI Slider 1.10.4 - * http://jqueryui.com - * - * Copyright 2014 jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - * - * http://api.jqueryui.com/slider/#theming - */ - -.ui-slider { - position: relative; - text-align: left; -} -.ui-slider .ui-slider-handle { - position: absolute; - z-index: 2; - width: 1.2em; - height: 1.2em; - cursor: default; -} -.ui-slider .ui-slider-range { - position: absolute; - z-index: 1; - font-size: .7em; - display: block; - border: 0; - background-position: 0 0; -} - -/* For IE8 - See #6727 */ -.ui-slider.ui-state-disabled .ui-slider-handle, -.ui-slider.ui-state-disabled .ui-slider-range { - filter: inherit; -} - -.ui-slider-horizontal { - height: 4px; -} -.ui-slider-horizontal .ui-slider-handle { - margin-left: -10px; - top: -7px; -} -.ui-slider-horizontal .ui-slider-range { - top: 0; - height: 100%; -} -.ui-slider-horizontal .ui-slider-range-min { - left: 0; -} -.ui-slider-horizontal .ui-slider-range-max { - right: 0; -} - -.ui-slider-vertical { - width: .8em; - height: 100px; -} -.ui-slider-vertical .ui-slider-handle { - left: -.3em; - margin-left: 0; - margin-bottom: -.6em; -} -.ui-slider-vertical .ui-slider-range { - left: 0; - width: 100%; -} -.ui-slider-vertical .ui-slider-range-min { - bottom: 0; -} -.ui-slider-vertical .ui-slider-range-max { - top: 0; -} - -/* Component containers -----------------------------------*/ -.ui-widget { - font-size: 1.1em/*{fsDefault}*/; -} -.ui-widget .ui-widget { - font-size: 1em; -} -.ui-widget input, -.ui-widget select, -.ui-widget textarea, -.ui-widget button { - font-size: 1em; -} -.ui-widget-content { - background-color: #E5E5E5; -} -.ui-widget-content a { - color: #222222/*{fcContent}*/; -} -.ui-widget-header { - background: #999999; - color: #222222; - font-weight: bold; -} -.ui-widget-header a { - color: #222222; -} - -.slider-primary .ui-widget-header{ - background-color: $primary-color; -} -.slider-info .ui-widget-header{ - background-color: $info-color; -} -.slider-success .ui-widget-header{ - background-color: $success-color; -} -.slider-warning .ui-widget-header{ - background-color: $warning-color; -} -.slider-danger .ui-widget-header{ - background-color: $danger-color; -} - -/* Interaction states -----------------------------------*/ -.ui-state-default, -.ui-widget-content .ui-state-default, -.ui-widget-header .ui-state-default { - background: rgb(255,255,255); /* Old browsers */ - background: -moz-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(241,241,242,1) 100%); /* FF3.6+ */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,1)), color-stop(100%,rgba(241,241,242,1))); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(241,241,242,1) 100%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(241,241,242,1) 100%); /* Opera 11.10+ */ - background: -ms-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(241,241,242,1) 100%); /* IE10+ */ - background: linear-gradient(to bottom, rgba(255,255,255,1) 0%,rgba(241,241,242,1) 100%); /* W3C */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#f1f1f2',GradientType=0 ); /* IE6-9 */ - - border-radius: 50%; - box-shadow: 0 1px 1px #FFFFFF inset, 0 1px 2px rgba(0, 0, 0, 0.4); - height:15px; - width:15px; - cursor:pointer; -} -.ui-state-default a, -.ui-state-default a:link, -.ui-state-default a:visited { - color: #555555/*{fcDefault}*/; - text-decoration: none; -} - -.ui-state-hover a, -.ui-state-hover a:hover, -.ui-state-hover a:link, -.ui-state-hover a:visited, -.ui-state-focus a, -.ui-state-focus a:hover, -.ui-state-focus a:link, -.ui-state-focus a:visited { - color: #212121/*{fcHover}*/; - text-decoration: none; -} -.ui-state-active a, -.ui-state-active a:link, -.ui-state-active a:visited { - color: #212121/*{fcActive}*/; - text-decoration: none; -} - -/* Interaction Cues -----------------------------------*/ -.ui-state-highlight, -.ui-widget-content .ui-state-highlight, -.ui-widget-header .ui-state-highlight { - border: 1px solid #fcefa1; - background: #fbf9ee; - color: #363636; -} -.ui-state-highlight a, -.ui-widget-content .ui-state-highlight a, -.ui-widget-header .ui-state-highlight a { - color: #363636; -} -.ui-state-error, -.ui-widget-content .ui-state-error, -.ui-widget-header .ui-state-error { - border: 1px solid $danger-color/*{borderColorError}*/; - background-color: $danger-color; - color: $danger-color/*{fcError}*/; -} -.ui-state-error a, -.ui-widget-content .ui-state-error a, -.ui-widget-header .ui-state-error a { - color: $danger-color/*{fcError}*/; -} -.ui-state-error-text, -.ui-widget-content .ui-state-error-text, -.ui-widget-header .ui-state-error-text { - color: $danger-color/*{fcError}*/; -} -.ui-priority-primary, -.ui-widget-content .ui-priority-primary, -.ui-widget-header .ui-priority-primary { - font-weight: bold; -} -.ui-priority-secondary, -.ui-widget-content .ui-priority-secondary, -.ui-widget-header .ui-priority-secondary { - opacity: .7; - filter:Alpha(Opacity=70); - font-weight: normal; -} -.ui-state-disabled, -.ui-widget-content .ui-state-disabled, -.ui-widget-header .ui-state-disabled { - opacity: .35; - filter:Alpha(Opacity=35); - background-image: none; -} -.ui-state-disabled .ui-icon { - filter:Alpha(Opacity=35); /* For IE8 - See #6059 */ -} \ No newline at end of file diff --git a/frontend/assets/sass/nomad-ui/_social-buttons.scss b/frontend/assets/sass/nomad-ui/_social-buttons.scss deleted file mode 100644 index 5e40c776..00000000 --- a/frontend/assets/sass/nomad-ui/_social-buttons.scss +++ /dev/null @@ -1,77 +0,0 @@ -.btn-social { - //@include btn-styles($default-color, $default-states-color); - opacity: 0.85; - padding: 8px 9px; - - .fa { - font-size: 18px; - width: 20px; - vertical-align: middle; - display: inline-block; - } - - &.btn-round { - padding: 8px; - } - - &.btn-simple { - padding: 8px 5px; - font-size: 16px; - - .fa{ - font-size: 20px; - position: relative; - top: -2px; - width: 24px; - } - } - -} - -.btn-facebook { - @include social-buttons-color($social-facebook); -} - -.btn-twitter { - @include social-buttons-color($social-twitter); -} - -.btn-pinterest { - @include social-buttons-color($social-pinterest); -} - -.btn-google { - @include social-buttons-color($social-google); -} - -.btn-linkedin { - @include social-buttons-color($social-linkedin); -} - -.btn-dribbble { - @include social-buttons-color($social-dribbble); -} - -.btn-github { - @include social-buttons-color($social-github); -} - -.btn-youtube { - @include social-buttons-color($social-youtube); -} - -.btn-stumbleupon { - @include social-buttons-color($social-stumbleupon); -} - -.btn-reddit { - @include social-buttons-color($social-reddit); -} - -.btn-tumblr { - @include social-buttons-color($social-tumblr); -} - -.btn-behance{ - @include social-buttons-color($social-behance); -} diff --git a/frontend/assets/sass/nomad-ui/_tables.scss b/frontend/assets/sass/nomad-ui/_tables.scss deleted file mode 100644 index cb33e48e..00000000 --- a/frontend/assets/sass/nomad-ui/_tables.scss +++ /dev/null @@ -1,120 +0,0 @@ -.table{ - - .radio, - .checkbox{ - position: relative; - height: 20px; - display: block; - width: 20px; - padding: 0px 0px; - margin: 0px 5px; - text-align: center; - - .icons{ - left: 5px; - } - } - > thead > tr > th, - > tbody > tr > th, - > tfoot > tr > th, - > thead > tr > td, - > tbody > tr > td, - > tfoot > tr > td{ - padding: 12px 8px; - vertical-align: middle; - border-color: $light-gray; - } - - > thead > tr > th{ - border-bottom-width: 1px; - font-size: $font-size-small; - text-transform: uppercase; - color: $dark-gray; - font-weight: $font-weight-normal; - padding-bottom: 5px; - } - - .td-actions .btn{ - @include opacity(0.36); - - &.btn-xs{ - padding-left: 3px; - padding-right: 3px; - } - } - .td-actions{ - min-width: 90px; - } - - > tbody > tr{ - position: relative; - - &:hover{ - .td-actions .btn{ - @include opacity(1); - } - } - } -} - -.table-bigboy{ - > thead > tr > th{ - font-size: $font-size-h6; - text-transform: uppercase; - color: $dark-gray; - font-weight: $font-weight-normal; - } - > tbody > tr > td{ - font-size: $font-size-base; - - b{ - display: block; - margin-bottom: 5px; - } - } - .td-name, - { - font-weight: $font-weight-light; - font-size: $font-size-h5; - } - .td-name{ - min-width: 240px; - } - .td-number{ - text-align: right; - min-width: 110px; - - small{ - margin-right: 3px; - } - } - - .td-actions{ - width: 60px; - min-width: auto; - - .btn{ - float: right; - } - } - .img-container{ - width: 180px; - height: 120px; - overflow: hidden; - display: block; - - border-radius: $border-radius-large; - - img{ - width: 100%; - } - } -} - -@include table-row-variant('success', $light-green); -@include table-row-variant('info', $light-azure); -@include table-row-variant('warning', $light-orange); -@include table-row-variant('danger', $light-red); - - - diff --git a/frontend/assets/sass/nomad-ui/_tabs-navs-pagination.scss b/frontend/assets/sass/nomad-ui/_tabs-navs-pagination.scss deleted file mode 100644 index 01701652..00000000 --- a/frontend/assets/sass/nomad-ui/_tabs-navs-pagination.scss +++ /dev/null @@ -1,302 +0,0 @@ -/* Navigation menu */ -.nav-pills { - > li + li { - margin-left: 0; - } - > li > a { - border: 1px solid $info-color; - border-radius: 0; - color: $info-color; - margin-left: -1px; - - &:hover, - &:focus{ - background-color: #F5F5F5; - } - } - > li.active > a, - > li.active > a:hover, - > li.active > a:focus { - background-color: $info-color; - color: #FFFFFF; - } - > li:first-child > a{ - border-radius: 4px 0 0 4px; - margin: 0; - } - > li:last-child > a{ - border-radius: 0 4px 4px 0; - } - -} - -.pagination > li.disabled{ - opacity: .4; -} - -.pagination.pagination-no-border > li > a, -.pagination.pagination-no-border > li > span{ - border: 0; -} -.pagination > li > a, -.pagination > li > span, -.pagination > li:first-child > a, -.pagination > li:first-child > span, -.pagination > li:last-child > a, -.pagination > li:last-child > span{ - border-radius: 50%; - margin: 0 2px; - color: $default-states-color; -} -.pagination > li.active > a, -.pagination > li.active > span, -.pagination > li.active > a:hover, -.pagination > li.active > span:hover, -.pagination > li.active > a:focus, -.pagination > li.active > span:focus { - background-color: $info-color; - border: 0; - color: #FFFFFF; - padding: 7px 13px; -} - -.nav-pills-blue{ - > li.active { - > a, - > a:hover, - > a:focus{ - background-color: $color-blue; - } - } -} - -.pagination-blue{ - > li.active{ - a, - a:hover, - a:focus, - span, - span:hover, - span:focus{ - background-color: $color-blue; - } - } -} - -.nav-pills-azure{ - > li.active { - > a, - > a:hover, - > a:focus{ - background-color: $color-azure; - } - } -} - -.pagination-azure{ - > li.active{ - a, - a:hover, - a:focus, - span, - span:hover, - span:focus{ - background-color: $color-azure; - } - } -} - -.nav-pills-green{ - > li.active { - > a, - > a:hover, - > a:focus{ - background-color: $color-green; - } - } -} - -.pagination-green{ - > li.active{ - a, - a:hover, - a:focus, - span, - span:hover, - span:focus{ - background-color: $color-green; - } - } -} - -.nav-pills-orange{ - > li.active { - > a, - > a:hover, - > a:focus{ - background-color: $color-orange; - } - } -} - -.pagination-orange{ - > li.active{ - a, - a:hover, - a:focus, - span, - span:hover, - span:focus{ - background-color: $color-orange; - } - } -} - -.nav-pills-red{ - > li.active { - > a, - > a:hover, - > a:focus{ - background-color: $color-red; - } - } -} - -.pagination-red{ - > li.active{ - a, - a:hover, - a:focus, - span, - span:hover, - span:focus{ - background-color: $color-red; - } - } -} - -.nav-pills-blue > li > a { - @include pill-style($color-blue); -} -.nav-pills-azure > li > a { - @include pill-style($color-azure); -} -.nav-pills-green > li > a { - @include pill-style($color-green); -} -.nav-pills-orange > li > a { - @include pill-style($color-orange); -} -.nav-pills-red > li > a { - @include pill-style($color-red); -} - -.nav-text, -.nav-icons{ - padding: $padding-default-vertical 0 0; - - > li > a{ - display: block; - padding: 0px $padding-base-horizontal; - color: $dark-gray; - text-align: center; - @include opacity(0.8); - - &:hover, - &:focus{ - background-color: $transparent-bg; - @include opacity(1); - } - } - > li:first-child a{ - padding-left: 0; - } - > li.active a{ - color: $info-color; - } -} - -.nav-icons > li{ - display: inline-block; - > a{ - padding: 0 10px; - margin-bottom: 10px; - } - > a i{ - font-size: $font-size-h4; - margin-bottom: 10px; - width: $font-size-h4; - } -} - -.nav-icons.nav-stacked > li{ - display: block; - > a { - margin-bottom: 20px; - } -} - -.nav-blue > li.active a{ - color: $primary-color; -} -.nav-azure > li.active a{ - color: $info-color; -} -.nav-green > li.active a{ - color: $success-color; -} -.nav-orange > li.active a{ - color: $warning-color; -} -.nav-red > li.active a{ - color: $danger-color; -} - -.nav-text{ - margin: $margin-bottom; - - > li > a{ - font-size: $font-size-h6; - text-transform: uppercase; - padding: 3px 0; - text-align: left; - font-weight: $font-weight-semi; - - } - > li:first-child > a{ - padding-top: 0; - } - h4{ - margin-top: 0; - } -} - -.nav-text:not(.nav-stacked){ - > li{ - display: inline-block; - } - > li > a{ - margin-right: 15px; - } -} - -.tab-pane { - padding: 15px 0; -} - -.nav-container{ - display: block; - width: 100%; - text-align: center; -} -.content-full-width{ - .nav-tabs{ - li:first-child{ - padding-left: $padding-default-horizontal; - } - } - .tab-pane{ - padding: $padding-default-horizontal; - } -} - diff --git a/frontend/assets/sass/nomad-ui/_tags.scss b/frontend/assets/sass/nomad-ui/_tags.scss deleted file mode 100644 index dd207dc2..00000000 --- a/frontend/assets/sass/nomad-ui/_tags.scss +++ /dev/null @@ -1,123 +0,0 @@ - -.tagsinput { - height: $height-base; - overflow-y: auto; - text-align: left; - .tag { - @extend .animation-transition-ultra-fast; - - cursor: pointer; - overflow: hidden; - position: relative; - margin: 5px 3px 5px 0; - @include label-style(); - } - - .tag:hover{ - padding-left: 10px; - padding-right: 14px; - } - - .tagsinput-add { - color: $black-color; - cursor: pointer; - display: inline-block; - font-size: 14px; - padding: 5px 6px; - margin: 5px 0 0; - vertical-align: top; - @include opacity(0.8); - - &:hover, - &:focus{ - @include opacity(1); - } - } - .tagsinput-add:before { - content: "\f067"; - font-family: "FontAwesome"; - } - - .tagsinput-remove-link { - @extend .animation-transition-ultra-fast; - - color: $default-color; - cursor: pointer; - font-size: 12px; - padding: 2px 0; - position: absolute; - right: 0; - opacity: 0; - text-align: right; - text-decoration: none; - top: 0; - width: 100%; - z-index: 2; - } - .tag:hover .tagsinput-remove-link { - opacity: 1; - padding-right: 6px; - } - .tagsinput-remove-link:before { - content: "\f00d"; - font-family: "FontAwesome"; - } - .tagsinput-add-container { - display: inline-block; - vertical-align: middle; - } - input{ - background: transparent; - border: none; - color: $black-color; - margin: 0; - outline: medium none !important; - padding: 0 0 0 5px; - vertical-align: top; - width: 30px; - height: 40px; - } - - &.tag-blue .tag, - &.tag-blue .tagsinput-remove-link{ - @include label-color($primary-color); - } - &.tag-azure .tag, - &.tag-azure .tagsinput-remove-link{ - @include label-color($info-color); - } - &.tag-green .tag, - &.tag-green .tagsinput-remove-link{ - @include label-color($success-color); - } - &.tag-orange .tag, - &.tag-orange .tagsinput-remove-link{ - @include label-color($warning-color); - } - &.tag-red .tag, - &.tag-red .tagsinput-remove-link{ - @include label-color($danger-color); - } - - &.tag-fill{ - &.tag-blue .tag{ - @include label-color-fill($primary-color); - } - &.tag-azure .tag{ - @include label-color-fill($info-color); - } - &.tag-green .tag{ - @include label-color-fill($success-color); - } - &.tag-orange .tag{ - @include label-color-fill($warning-color); - } - &.tag-red .tag{ - @include label-color-fill($danger-color); - } - } - &.tag-fill .tagsinput-remove-link{ - color: $white-color; - } - -} diff --git a/frontend/assets/sass/nomad-ui/_tooltips-and-popovers.scss b/frontend/assets/sass/nomad-ui/_tooltips-and-popovers.scss deleted file mode 100644 index 70547db5..00000000 --- a/frontend/assets/sass/nomad-ui/_tooltips-and-popovers.scss +++ /dev/null @@ -1,156 +0,0 @@ -.tooltip { - font-size: $font-size-base; - font-weight: $font-weight-bold; - - &.top { - margin-top: -11px; - padding: 0; - } - &.top .tooltip-inner:after { - border-top: 11px solid #FAE6A4; - border-left: 11px solid rgba(0, 0, 0, 0); - border-right: 11px solid rgba(0, 0, 0, 0); - bottom: -10px; - } - &.top .tooltip-inner:before { - border-top: 11px solid rgba(0, 0, 0, 0.2); - border-left: 11px solid rgba(0, 0, 0, 0); - border-right: 11px solid rgba(0, 0, 0, 0); - bottom: -11px; - } - &.bottom { - margin-top: 11px; - padding: 0; - } - &.bottom .tooltip-inner:after { - border-bottom: 11px solid #FAE6A4; - border-left: 11px solid rgba(0, 0, 0, 0); - border-right: 11px solid rgba(0, 0, 0, 0); - top: -10px; - } - &.bottom .tooltip-inner:before { - border-bottom: 11px solid rgba(0, 0, 0, 0.2); - border-left: 11px solid rgba(0, 0, 0, 0); - border-right: 11px solid rgba(0, 0, 0, 0); - top: -11px; - } - &.left{ - margin-left: -11px; - padding: 0; - } - &.left .tooltip-inner:after { - border-left: 11px solid #FAE6A4; - border-top: 11px solid rgba(0, 0, 0, 0); - border-bottom: 11px solid rgba(0, 0, 0, 0); - right: -10px; - left: auto; - margin-left: 0; - } - &.left .tooltip-inner:before { - border-left: 11px solid rgba(0, 0, 0, 0.2); - border-top: 11px solid rgba(0, 0, 0, 0); - border-bottom: 11px solid rgba(0, 0, 0, 0); - right: -11px; - left: auto; - margin-left: 0; - } - &.right{ - margin-left: 11px; - padding: 0; - } - &.right .tooltip-inner:after { - border-right: 11px solid #FAE6A4; - border-top: 11px solid rgba(0, 0, 0, 0); - border-bottom: 11px solid rgba(0, 0, 0, 0); - left: -10px; - top: 0; - margin-left: 0; - } - &.right .tooltip-inner:before { - border-right: 11px solid rgba(0, 0, 0, 0.2); - border-top: 11px solid rgba(0, 0, 0, 0); - border-bottom: 11px solid rgba(0, 0, 0, 0); - left: -11px; - top: 0; - margin-left: 0; - } -} - -.tooltip-arrow{ - display: none; - opacity: 0; -} -.tooltip-inner { - background-color: #FAE6A4; - border-radius: 4px; - box-shadow: 0 1px 13px rgba(0, 0, 0, 0.14), 0 0 0 1px rgba(115, 71, 38, 0.23); - color: #734726; - max-width: 280px; - min-width: 90px; - padding: 6px 10px; - text-align: center; - text-decoration: none; -} -.tooltip-inner:after { - content: ""; - display: inline-block; - left: 100%; - margin-left: -60%; - position: absolute; -} -.tooltip-inner:before { - content: ""; - display: inline-block; - left: 100%; - margin-left: -60%; - position: absolute; -} - -.popover{ - padding: 0; - border-radius: $border-radius-extreme; - z-index: 1031; - border: 0; - @include box-shadow(none); -} -.popover-title{ - font-size: $font-paragraph; - background-color: $azure-navbar; - font-weight: normal; - line-height: 22px; - padding: 8px 15px; - margin: 0; - color: $white-color; - text-align: center; - border-radius: $border-radius-extreme $border-radius-extreme 0 0; -} -.popover-content{ - padding: 9px 15px; -} -.popover .arrow{ - border: 0; -} -.popover.top .arrow{ - margin-left: 0; -} -.popover.bottom .arrow:after{ - border-bottom-color: $azure-navbar; -} -.popover-filter{ - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1030; - background-color: #000000; - @include opacity(0); - visibility: hidden; - - transition: visibility 0s linear 0.3s,opacity 0.3s linear; -} -.popover-filter.in{ - visibility:visible; - @include opacity(0.2); - transition-delay: 0s; -} \ No newline at end of file diff --git a/frontend/assets/sass/nomad-ui/_typography.scss b/frontend/assets/sass/nomad-ui/_typography.scss deleted file mode 100644 index 6e181beb..00000000 --- a/frontend/assets/sass/nomad-ui/_typography.scss +++ /dev/null @@ -1,93 +0,0 @@ -/* Font Smoothing */ -body, -h1, .h1, -h2, .h2, -h3, .h3, -h4, .h4, -h5, .h5, -h6, .h6, -p, -.navbar, -.brand, -.btn-simple, -.alert, -a, -.td-name, -td, -button.close{ - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - font-family: "Roboto","Helvetica Neue",Arial,sans-serif; - font-weight: $font-weight-normal; -} - -h1, .h1, h2, .h2, h3, .h3, h4, .h4{ - font-weight: $font-weight-light; - margin: $margin-large-vertical 0 $margin-base-vertical; -} - -h1, .h1 { - font-size: $font-size-h1; -} -h2, .h2{ - font-size: $font-size-h2; -} -h3, .h3{ - font-size: $font-size-h3; - margin: 20px 0 10px; -} -h4, .h4{ - font-size: $font-size-h4; - line-height: 30px; -} -h5, .h5 { - font-size: $font-size-h5; - margin-bottom: 15px; -} -h6, .h6{ - font-size: $font-size-h6; - font-weight: $font-weight-bold; - text-transform: uppercase; -} -p{ - font-size: $font-paragraph; - line-height: $line-height-general; -} - -h1 small, h2 small, h3 small, h4 small, h5 small, h6 small, .h1 small, .h2 small, .h3 small, .h4 small, .h5 small, .h6 small, h1 .small, h2 .small, h3 .small, h4 .small, h5 .small, h6 .small, .h1 .small, .h2 .small, .h3 .small, .h4 .small, .h5 .small, .h6 .small { - color: $dark-gray; - font-weight: $font-weight-light; - line-height: $line-height-general; -} - -h1 small, h2 small, h3 small, h1 .small, h2 .small, h3 .small { - font-size: 60%; -} - -h1 .subtitle{ - display: block; - margin: 0 0 $margin-large-vertical; -} - -.text-muted{ - color: #9A9A9A; -} -.text-primary, .text-primary:hover{ - color: #1D62F0 !important; -} -.text-info, .text-info:hover{ - color: $info-color !important; -} -.text-success, .text-success:hover{ - color: $success-color !important; -} -.text-warning, .text-warning:hover{ - color: $warning-color !important; -} -.text-danger, .text-danger:hover{ - color: $danger-color !important; -} - -.text-space{ - padding: 70px 0; -} diff --git a/frontend/assets/sass/nomad-ui/_variables.scss b/frontend/assets/sass/nomad-ui/_variables.scss deleted file mode 100644 index 2bb62212..00000000 --- a/frontend/assets/sass/nomad-ui/_variables.scss +++ /dev/null @@ -1,320 +0,0 @@ -// General Colors - - -$color-azure: #23CCEF; -$color-purple: #9368E9; -$color-red: #FB404B; -$color-green: #87CB16; -$color-orange: #FFA534; -$color-blue: #447DF7; -$color-black: #5e5e5e; -$color-nomad: #449b82; -$color-nomad-dark: darken($color-nomad, 20%) !default; - -/* light colors */ - -$light-blue: rgba($color-blue, .2); -$light-azure: rgba($color-azure, .2); -$light-green: rgba($color-green, .2); -$light-orange: rgba($color-orange, .2); -$light-red: rgba($color-red, .2); - - -$default-color: #888888 !default; - -$black-color: #333333 !default; -$black-hr: #444444 !default; - -$light-gray: #E3E3E3 !default; -$medium-gray: #DDDDDD !default; -$placeholder-gray: #C3C3C3 !default; -$medium-dark-gray: #AAAAAA !default; -$dark-gray: #9A9A9A !default; - -// Gradients colors - -$default-color-top: #d9d9d9; -$default-color-bottom: #909297; - -$blue-color-top: #4087ea; -$blue-color-bottom: #533ce1; - -$azure-color-top: #45c0fd; -$azure-color-bottom: #4091ff; - -$green-color-top: #a1eb3a; -$green-color-bottom: #6dc030; - -$orange-color-top: #ffb33b; -$orange-color-bottom: #ec1657; - -$red-color-top: #ff3b30; -$red-color-bottom: #bb0502; - -$purple-color-top: #df55e1; -$purple-color-bottom: #943bea; - -$pink-color-top: #ff2a63; -$pink-color-bottom: #ff2e2e; - -$black-color-top: #787878; -$black-color-bottom: #343434; - - -$social-facebook: #3b5998; -$social-twitter: #55acee; -$social-pinterest: #cc2127; -$social-google: #dd4b39; -$social-linkedin: #0976b4; -$social-dribbble: #ea4c89; -$social-github: #333333; -$social-youtube: #e52d27; -$social-stumbleupon: #eb4924; -$social-reddit: #ff4500; -$social-tumblr: #35465c; -$social-behance: #1769ff; - - -$filter-blue: darken($color-blue, 10%); -$filter-azure: darken($color-azure, 10%); -$filter-green: darken($color-green, 10%); -$filter-orange: darken($color-orange, 10%); -$filter-red: darken($color-red, 10%); - - -$white-navbar: rgba(#FFFFFF, .96); -$blue-navbar: lighten($color-blue, 10%); -$azure-navbar: lighten($color-azure, 15%); -$green-navbar: lighten($color-green, 10%); -$orange-navbar: lighten($color-orange, 10%); -$red-navbar: lighten($color-red, 10%); - - - - -//== Buttons -// -//## For each of Bootstrap's buttons, define text, background and border color. - -$none: 0 !default; -$border-thin: 1px !default; -$border-thick: 2px !default; - -$white-color: #FFFFFF !default; -$white-bg: #FFFFFF !default; - -$smoke-bg: #F5F5F5 !default; - -$black-bg: rgba(30,30,30,.97) !default; - -$transparent-bg: transparent !default; - - -$default-bg: $default-color !default; -$default-states-color: darken($default-color, 6%) !default; - -$primary-color: $color-blue !default; -$primary-bg: $color-blue !default; -$primary-states-color: darken($color-blue, 5%) !default; - -$info-color: $color-azure !default; -$info-bg: $color-azure !default; -$info-states-color: darken($info-bg, 5%) !default; - -$success-color: $color-green !default; -$success-bg: $color-green !default; -$success-states-color: darken($color-green, 5%) !default; - -$warning-color: $color-orange !default; -$warning-bg: $color-orange !default; -$warning-states-color: darken($color-orange, 7%) !default; - - -$danger-color: $color-red !default; -$danger-bg: $color-red !default; -$danger-states-color: darken($color-red, 8%) !default; - -$link-disabled-color: #666666 !default; - - -//== Components -// - -$padding-default-vertical: 10px !default; -$padding-default-horizontal: 15px !default; - - -$padding-base-vertical: 8px !default; -$padding-base-horizontal: 16px !default; - -$padding-round-vertical: 8px !default; -$padding-round-horizontal: 16px !default; - -$padding-simple-vertical: 9px !default; -$padding-simple-horizontal: 16px !default; - -$padding-large-vertical: 14px !default; -$padding-large-horizontal: 30px !default; - -$padding-small-vertical: 5px !default; -$padding-small-horizontal: 10px !default; - -$padding-xs-vertical: 1px !default; -$padding-xs-horizontal: 5px !default; - -$padding-label-vertical: 2px !default; -$padding-label-horizontal: 12px !default; - -$margin-large-vertical: 30px !default; -$margin-base-vertical: 15px !default; - -$margin-base: 15px !default; - -$padding-zero: 0px !default; - -$margin-bottom: 0 0 10px 0 !default; -$border-radius-small: 3px !default; -$border-radius-base: 4px !default; -$border-radius-large: 6px !default; -$border-radius-extreme: 10px !default; - -$border-radius-large-top: $border-radius-large $border-radius-large 0 0 !default; -$border-radius-large-bottom: 0 0 $border-radius-large $border-radius-large !default; - -$btn-round-radius: 30px !default; - -$height-base: 40px !default; - -$font-size-base: 14px !default; -$font-size-small: 12px !default; -$font-size-medium: 16px !default; -$font-size-large: 18px !default; -$font-size-large-navbar: 20px !default; - -$font-size-h1: 52px !default; -$font-size-h2: 36px !default; -$font-size-h3: 28px !default; -$font-size-h4: 22px !default; -$font-size-h5: 18px !default; -$font-size-h6: 14px !default; -$font-paragraph: 16px !default; -$font-size-navbar: 16px !default; -$font-size-small: 12px !default; - -$font-weight-light: 300 !default; -$font-weight-normal: 400 !default; -$font-weight-semi: 500 !default; -$font-weight-bold: 600 !default; - -$line-height-general: 1.5 !default; -$line-height: 20px !default; -$line-height-lg: 54px !default; - -$sidebar-width: calc(100% - 260px) !default; - - -$border-radius-top: 10px 10px 0 0 !default; -$border-radius-bottom: 0 0 10px 10px !default; - -$dropdown-shadow: 1px 2px 3px rgba(0, 0, 0, 0.125); - -$general-transition-time: 300ms !default; - -$slow-transition-time: 370ms !default; -$dropdown-coordinates: 29px -50px !default; - -$fast-transition-time: 150ms !default; -$ultra-fast-transition-time: 60ms !default; - -$select-coordinates: 50% -40px !default; - -$transition-linear: linear !default; -$transition-bezier: cubic-bezier(0.34, 1.61, 0.7, 1) !default; -$transition-ease: ease 0s; -$transition-ease-in: ease-in !default; -$transition-ease-out: ease-out !default; - - -$navbar-padding-a: 10px 15px; -$navbar-margin-a: 10px 3px; - -$padding-social-a: 10px 5px; - -$navbar-margin-a-btn: 15px 3px; -$navbar-margin-a-btn-round: 16px 3px; - -$navbar-padding-a-icons: 6px 15px; -$navbar-margin-a-icons: 6px 3px; - -$navbar-padding-brand: 15px 15px; -$navbar-margin-brand: 7px 0px; - -$navbar-margin-brand-icons: 12px auto; - -$navbar-margin-btn: 10px 3px; - -$height-icon: 64px !default; -$width-icon: 64px !default; -$padding-icon: 12px !default; -$border-radius-icon: 15px !default; - -$size-icon: 64px; -$size-icon-sm: 32px; - -$height-icon-sm: 32px; -$width-icon-sm: 32px; -$padding-icon-sm: 4px; -$border-radius-icon-sm: 7px; - -$height-icon-message: 40px; -$width-icon-message: 40px; - -$height-icon-message-sm: 20px; -$width-icon-message-sm: 20px; - - - -$topbar-x: topbar-x !default; -$topbar-back: topbar-back !default; -$bottombar-x: bottombar-x !default; -$bottombar-back: bottombar-back !default; - - - -//== Media queries breakpoints -// -//## Define the breakpoints at which your layout will change, adapting to different screen sizes. - -// Extra small screen / phone -//** Deprecated `$screen-xs` as of v3.0.1 -$screen-xs: 480px !default; -//** Deprecated `$screen-xs-min` as of v3.2.0 -$screen-xs-min: $screen-xs !default; -//** Deprecated `$screen-phone` as of v3.0.1 -$screen-phone: $screen-xs-min !default; - -// Small screen / tablet -//** Deprecated `$screen-sm` as of v3.0.1 -$screen-sm: 768px !default; -$screen-sm-min: $screen-sm !default; -//** Deprecated `$screen-tablet` as of v3.0.1 -$screen-tablet: $screen-sm-min !default; - -// Medium screen / desktop -//** Deprecated `$screen-md` as of v3.0.1 -$screen-md: 992px !default; -$screen-md-min: $screen-md !default; -//** Deprecated `$screen-desktop` as of v3.0.1 -$screen-desktop: $screen-md-min !default; - -// Large screen / wide desktop -//** Deprecated `$screen-lg` as of v3.0.1 -$screen-lg: 1200px !default; -$screen-lg-min: $screen-lg !default; -//** Deprecated `$screen-lg-desktop` as of v3.0.1 -$screen-lg-desktop: $screen-lg-min !default; - -// So media queries don't overlap when required, provide a maximum -$screen-xs-max: ($screen-sm-min - 1) !default; -$screen-sm-max: ($screen-md-min - 1) !default; -$screen-md-max: ($screen-lg-min - 1) !default; diff --git a/frontend/assets/sass/nomad-ui/mixins/_buttons.scss b/frontend/assets/sass/nomad-ui/mixins/_buttons.scss deleted file mode 100644 index 21c0696a..00000000 --- a/frontend/assets/sass/nomad-ui/mixins/_buttons.scss +++ /dev/null @@ -1,74 +0,0 @@ -// Mixin for generating new styles -@mixin btn-styles($btn-color, $btn-states-color) { - border-color: $btn-color; - color: $btn-color; - - &:hover, - &:focus, - &:active, - &.active, - &:active:focus, - &:active:hover, - &.active:focus, - &.active:hover, - .open > &.dropdown-toggle { - background-color: $transparent-bg; - color: $btn-states-color; - border-color: $btn-states-color; - } - - &.disabled, - &:disabled, - &[disabled], - fieldset[disabled] & { - &, - &:hover, - &:focus, - &.focus, - &:active, - &.active { - background-color: $transparent-bg; - border-color: $btn-color; - } - } - - - &.btn-fill { - color: $white-color; - background-color: $btn-color; - @include opacity(1); - - &:hover, - &:focus, - &:active, - &.active, - .open > &.dropdown-toggle{ - background-color: $btn-states-color; - color: $white-color; - } - - .caret{ - border-top-color: $white-color; - } - } - - .caret{ - border-top-color: $btn-color; - } -} - - -@mixin btn-size($padding-vertical, $padding-horizontal, $font-size, $border){ - font-size: $font-size; - border-radius: $border; - padding: $padding-vertical $padding-horizontal; - - &.btn-round{ - padding: $padding-vertical + 1 $padding-horizontal; - } - - &.btn-simple{ - padding: $padding-vertical + 2 $padding-horizontal; - } - -} \ No newline at end of file diff --git a/frontend/assets/sass/nomad-ui/mixins/_cards.scss b/frontend/assets/sass/nomad-ui/mixins/_cards.scss deleted file mode 100644 index af1f955a..00000000 --- a/frontend/assets/sass/nomad-ui/mixins/_cards.scss +++ /dev/null @@ -1,8 +0,0 @@ -@mixin filter($color){ - @if $color == #FFFFFF{ - background-color: rgba($color,.91); - } @else { - background-color: rgba($color,.69); - } -} - diff --git a/frontend/assets/sass/nomad-ui/mixins/_chartist.scss b/frontend/assets/sass/nomad-ui/mixins/_chartist.scss deleted file mode 100644 index 1e6b6c0e..00000000 --- a/frontend/assets/sass/nomad-ui/mixins/_chartist.scss +++ /dev/null @@ -1,85 +0,0 @@ -// Scales for responsive SVG containers -$ct-scales: ((1), (15/16), (8/9), (5/6), (4/5), (3/4), (2/3), (5/8), (1/1.618), (3/5), (9/16), (8/15), (1/2), (2/5), (3/8), (1/3), (1/4)) !default; -$ct-scales-names: (ct-square, ct-minor-second, ct-major-second, ct-minor-third, ct-major-third, ct-perfect-fifth, ct-minor-sixth, ct-golden-section, ct-major-sixth, ct-minor-seventh, ct-major-seventh, ct-octave, ct-major-tenth, ct-major-eleventh, ct-major-twelfth, ct-double-octave) !default; - -// Class names to be used when generating CSS -$ct-class-chart: ct-chart !default; -$ct-class-chart-line: ct-chart-line !default; -$ct-class-chart-bar: ct-chart-bar !default; -$ct-class-horizontal-bars: ct-horizontal-bars !default; -$ct-class-chart-pie: ct-chart-pie !default; -$ct-class-chart-donut: ct-chart-donut !default; -$ct-class-label: ct-label !default; -$ct-class-series: ct-series !default; -$ct-class-line: ct-line !default; -$ct-class-point: ct-point !default; -$ct-class-area: ct-area !default; -$ct-class-bar: ct-bar !default; -$ct-class-slice-pie: ct-slice-pie !default; -$ct-class-slice-donut: ct-slice-donut !default; -$ct-class-grid: ct-grid !default; -$ct-class-vertical: ct-vertical !default; -$ct-class-horizontal: ct-horizontal !default; -$ct-class-start: ct-start !default; -$ct-class-end: ct-end !default; - -// Container ratio -$ct-container-ratio: (1/1.618) !default; - -// Text styles for labels -$ct-text-color: rgba(0, 0, 0, 0.4) !default; -$ct-text-size: 1.3rem !default; -$ct-text-align: flex-start !default; -$ct-text-justify: flex-start !default; -$ct-text-line-height: 1; - -// Grid styles -$ct-grid-color: rgba(0, 0, 0, 0.2) !default; -$ct-grid-dasharray: 2px !default; -$ct-grid-width: 1px !default; - -// Line chart properties -$ct-line-width: 3px !default; -$ct-line-dasharray: false !default; -$ct-point-size: 8px !default; -// Line chart point, can be either round or square -$ct-point-shape: round !default; -// Area fill transparency between 0 and 1 -$ct-area-opacity: 0.8 !default; - -// Bar chart bar width -$ct-bar-width: 10px !default; - -// Donut width (If donut width is to big it can cause issues where the shape gets distorted) -$ct-donut-width: 60px !default; - -// If set to true it will include the default classes and generate CSS output. If you're planning to use the mixins you -// should set this property to false -$ct-include-classes: true !default; - -// If this is set to true the CSS will contain colored series. You can extend or change the color with the -// properties below -$ct-include-colored-series: $ct-include-classes !default; - -// If set to true this will include all responsive container variations using the scales defined at the top of the script -$ct-include-alternative-responsive-containers: $ct-include-classes !default; - -// Series names and colors. This can be extended or customized as desired. Just add more series and colors. -$ct-series-names: (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) !default; -$ct-series-colors: ( - $color-azure, - $color-red, - $color-orange, - $color-purple, - $color-green, - $color-blue, - $color-black, - $social-google, - $social-tumblr, - $social-youtube, - $social-twitter, - $social-pinterest, - $social-behance, - #6188e2, - #a748ca -) !default; diff --git a/frontend/assets/sass/nomad-ui/mixins/_icons.scss b/frontend/assets/sass/nomad-ui/mixins/_icons.scss deleted file mode 100644 index 80df4dff..00000000 --- a/frontend/assets/sass/nomad-ui/mixins/_icons.scss +++ /dev/null @@ -1,13 +0,0 @@ -@mixin icon-background ($icon-url){ - background-image : url($icon-url); - -} - -@mixin icon-shape ($size, $padding, $border-radius) { - height: $size; - width: $size; - padding: $padding; - border-radius: $border-radius; - display: inline-table; - -} \ No newline at end of file diff --git a/frontend/assets/sass/nomad-ui/mixins/_inputs.scss b/frontend/assets/sass/nomad-ui/mixins/_inputs.scss deleted file mode 100644 index 870c918c..00000000 --- a/frontend/assets/sass/nomad-ui/mixins/_inputs.scss +++ /dev/null @@ -1,17 +0,0 @@ -@mixin input-size($padding-vertical, $padding-horizontal, $height){ - padding: $padding-vertical $padding-horizontal; - height: $height; -} - -@mixin placeholder($color, $opacity){ - color: $color; - @include opacity(1); -} - -@mixin light-form(){ - border-radius: 0; - border:0; - padding: 0; - background-color: transparent; - -} \ No newline at end of file diff --git a/frontend/assets/sass/nomad-ui/mixins/_labels.scss b/frontend/assets/sass/nomad-ui/mixins/_labels.scss deleted file mode 100644 index 8a2bdd5d..00000000 --- a/frontend/assets/sass/nomad-ui/mixins/_labels.scss +++ /dev/null @@ -1,21 +0,0 @@ -@mixin label-style(){ - padding: $padding-label-vertical $padding-label-horizontal; - border: 1px solid $default-color; - border-radius: $border-radius-small; - color: $default-color; - font-weight: $font-weight-semi; - font-size: $font-size-small; - text-transform: uppercase; - display: inline-block; - vertical-align: middle; -} - -@mixin label-color($color){ - border-color: $color; - color: $color; -} -@mixin label-color-fill($color){ - border-color: $color; - color: $white-color; - background-color: $color; -} \ No newline at end of file diff --git a/frontend/assets/sass/nomad-ui/mixins/_morphing-buttons.scss b/frontend/assets/sass/nomad-ui/mixins/_morphing-buttons.scss deleted file mode 100644 index 1a4e986d..00000000 --- a/frontend/assets/sass/nomad-ui/mixins/_morphing-buttons.scss +++ /dev/null @@ -1,34 +0,0 @@ -$prefixes: ('', '-moz-', '-webkit-', '-ms-') !default; - -@mixin circle-animation(){ - @for $i from 0 to length($prefixes) { - @include circle-animation-details(nth($prefixes, $i + 1)); - } -} - -@mixin circle-animation-details($name){ - #{$name}animation-name: spin; - #{$name}animation-duration: 1250ms; - #{$name}animation-iteration-count: infinite; - #{$name}animation-timing-function: linear; - -} -@keyframes spin { - from { transform:rotate(0deg); } - to { transform:rotate(360deg); } -} - -@-webkit-keyframes spin { - from { -webkit-transform: rotate(0deg); } - to { -webkit-transform: rotate(360deg); } -} - -@-moz-keyframes spin { - from { -moz-transform: rotate(0deg); } - to { -moz-transform: rotate(360deg); } -} - -@-ms-keyframes spin { - from { -ms-transform: rotate(0deg); } - to { -ms-transform: rotate(360deg); } -} \ No newline at end of file diff --git a/frontend/assets/sass/nomad-ui/mixins/_navbars.scss b/frontend/assets/sass/nomad-ui/mixins/_navbars.scss deleted file mode 100644 index 6f500463..00000000 --- a/frontend/assets/sass/nomad-ui/mixins/_navbars.scss +++ /dev/null @@ -1,11 +0,0 @@ -@mixin navbar-color($color){ - background-color: $color; -} - -@mixin center-item(){ - left: 0; - right: 0; - margin-right: auto; - margin-left: auto; - position: absolute; -} \ No newline at end of file diff --git a/frontend/assets/sass/nomad-ui/mixins/_social-buttons.scss b/frontend/assets/sass/nomad-ui/mixins/_social-buttons.scss deleted file mode 100644 index 38a7d4bd..00000000 --- a/frontend/assets/sass/nomad-ui/mixins/_social-buttons.scss +++ /dev/null @@ -1,43 +0,0 @@ -@mixin social-buttons-color ($color){ - - border-color: $color; - color: $color; - - &:hover, - &:focus, - &:active, - &.active, - .open > &.dropdown-toggle { - background-color: $transparent-bg; - color: $color; - border-color: $color; - opacity: 1; - } - - &:disabled, - &[disabled], - &.disabled { - background-color: $transparent-bg; - border-color: $color; - } - - &.btn-fill { - color: $white-color; - background-color: $color; - opacity: 0.9; - - &:hover, - &:focus, - &:active, - &.active, - .open > &.dropdown-toggle{ - background-color: $color; - color: $white-color; - opacity: 1; - } - - } - - -} - \ No newline at end of file diff --git a/frontend/assets/sass/nomad-ui/mixins/_table-row.scss b/frontend/assets/sass/nomad-ui/mixins/_table-row.scss deleted file mode 100644 index 30f99c3f..00000000 --- a/frontend/assets/sass/nomad-ui/mixins/_table-row.scss +++ /dev/null @@ -1,22 +0,0 @@ -@mixin table-row-variant($state, $background) { - .table > thead > tr, - .table > tbody > tr, - .table > tfoot > tr { - > td.#{$state}, - > th.#{$state}, - &.#{$state} > td, - &.#{$state} > th { - background-color: $background; - } - } - - .table-hover > tbody > tr { - > td.#{$state}:hover, - > th.#{$state}:hover, - &.#{$state}:hover > td, - &:hover > .#{$state}, - &.#{$state}:hover > th { - background-color: lighten($background, 3%); - } - } -} \ No newline at end of file diff --git a/frontend/assets/sass/nomad-ui/mixins/_tabs.scss b/frontend/assets/sass/nomad-ui/mixins/_tabs.scss deleted file mode 100644 index edf6f580..00000000 --- a/frontend/assets/sass/nomad-ui/mixins/_tabs.scss +++ /dev/null @@ -1,4 +0,0 @@ -@mixin pill-style($color){ - border: 1px solid $color; - color: $color; -} \ No newline at end of file diff --git a/frontend/assets/sass/nomad-ui/mixins/_transparency.scss b/frontend/assets/sass/nomad-ui/mixins/_transparency.scss deleted file mode 100644 index da32b745..00000000 --- a/frontend/assets/sass/nomad-ui/mixins/_transparency.scss +++ /dev/null @@ -1,20 +0,0 @@ -// Opacity - -@mixin opacity($opacity) { - opacity: $opacity; - // IE8 filter - $opacity-ie: ($opacity * 100); - filter: #{alpha(opacity=$opacity-ie)}; -} - -@mixin black-filter($opacity){ - top: 0; - left: 0; - height: 100%; - width: 100%; - position: absolute; - background-color: rgba(17,17,17,$opacity); - display: block; - content: ""; - z-index: 1; -} \ No newline at end of file diff --git a/frontend/assets/sass/nomad-ui/mixins/_vendor-prefixes.scss b/frontend/assets/sass/nomad-ui/mixins/_vendor-prefixes.scss deleted file mode 100644 index 275c2fb0..00000000 --- a/frontend/assets/sass/nomad-ui/mixins/_vendor-prefixes.scss +++ /dev/null @@ -1,197 +0,0 @@ -// User select -// For selecting text on the page - -@mixin user-select($select) { - -webkit-user-select: $select; - -moz-user-select: $select; - -ms-user-select: $select; // IE10+ - user-select: $select; -} - -@mixin box-shadow($shadow...) { - -webkit-box-shadow: $shadow; // iOS <4.3 & Android <4.1 - box-shadow: $shadow; -} - -// Box sizing -@mixin box-sizing($boxmodel) { - -webkit-box-sizing: $boxmodel; - -moz-box-sizing: $boxmodel; - box-sizing: $boxmodel; -} - - -@mixin transition($time, $type){ - -webkit-transition: all $time $type; - -moz-transition: all $time $type; - -o-transition: all $time $type; - -ms-transition: all $time $type; - transition: all $time $type; -} - -@mixin transform-scale($value){ - -webkit-transform: scale($value); - -moz-transform: scale($value); - -o-transform: scale($value); - -ms-transform: scale($value); - transform: scale($value); -} - -@mixin transform-translate-x($value){ - -webkit-transform: translate3d($value, 0, 0); - -moz-transform: translate3d($value, 0, 0); - -o-transform: translate3d($value, 0, 0); - -ms-transform: translate3d($value, 0, 0); - transform: translate3d($value, 0, 0); -} - -@mixin transform-translate-y($value){ - -webkit-transform: translate3d(0, $value, 0); - -moz-transform: translate3d(0, $value, 0); - -o-transform: translate3d(0, $value, 0); - -ms-transform: translate3d(0, $value, 0); - transform: translate3d(0, $value, 0); -} - -@mixin transform-origin($coordinates){ - -webkit-transform-origin: $coordinates; - -moz-transform-origin: $coordinates; - -o-transform-origin: $coordinates; - -ms-transform-origin: $coordinates; - transform-origin: $coordinates; -} - -@mixin line-gradient($top-color, $bottom-color){ - background: $top-color; - background: -moz-linear-gradient(top, $top-color 0%, $bottom-color 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,$top-color), color-stop(100%,$bottom-color)); - background: -webkit-linear-gradient(top, $top-color 0%,$bottom-color 100%); - background: -o-linear-gradient(top, $top-color 0%,$bottom-color 100%); - background: -ms-linear-gradient(top, $top-color 0%,$bottom-color 100%); - background: linear-gradient(to bottom, $top-color 0%,$bottom-color 100%); - background-size: 150% 150%; -} - -@mixin radial-gradient($extern-color, $center-color){ - background: $extern-color; - background: -moz-radial-gradient(center, ellipse cover, $center-color 0%, $extern-color 100%); /* FF3.6+ */ - background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%,$center-color), color-stop(100%,$extern-color)); /* Chrome,Safari4+ */ - background: -webkit-radial-gradient(center, ellipse cover, $center-color 0%,$extern-color 100%); /* Chrome10+,Safari5.1+ */ - background: -o-radial-gradient(center, ellipse cover, $center-color 0%,$extern-color 100%); /* Opera 12+ */ - background: -ms-radial-gradient(center, ellipse cover, $center-color 0%,$extern-color 100%); /* IE10+ */ - background: radial-gradient(ellipse at center, $center-color 0%,$extern-color 100%); /* W3C */ - background-size: 550% 450%; -} - -@mixin vertical-align { - position: relative; - top: 50%; - -webkit-transform: translateY(-50%); - -ms-transform: translateY(-50%); - transform: translateY(-50%); -} - -@mixin rotate-180(){ - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); - -webkit-transform: rotate(180deg); - -ms-transform: rotate(180deg); - transform: rotate(180deg); -} - -@mixin bar-animation($type){ - -webkit-animation: $type 500ms linear 0s; - -moz-animation: $type 500ms linear 0s; - animation: $type 500ms 0s; - -webkit-animation-fill-mode: forwards; - -moz-animation-fill-mode: forwards; - animation-fill-mode: forwards; -} - -@mixin topbar-x-rotation(){ - @keyframes topbar-x { - 0% {top: 0px; transform: rotate(0deg); } - 45% {top: 6px; transform: rotate(145deg); } - 75% {transform: rotate(130deg); } - 100% {transform: rotate(135deg); } - } - @-webkit-keyframes topbar-x { - 0% {top: 0px; -webkit-transform: rotate(0deg); } - 45% {top: 6px; -webkit-transform: rotate(145deg); } - 75% {-webkit-transform: rotate(130deg); } - 100% { -webkit-transform: rotate(135deg); } - } - @-moz-keyframes topbar-x { - 0% {top: 0px; -moz-transform: rotate(0deg); } - 45% {top: 6px; -moz-transform: rotate(145deg); } - 75% {-moz-transform: rotate(130deg); } - 100% { -moz-transform: rotate(135deg); } - } -} - -@mixin topbar-back-rotation(){ - @keyframes topbar-back { - 0% { top: 6px; transform: rotate(135deg); } - 45% { transform: rotate(-10deg); } - 75% { transform: rotate(5deg); } - 100% { top: 0px; transform: rotate(0); } - } - - @-webkit-keyframes topbar-back { - 0% { top: 6px; -webkit-transform: rotate(135deg); } - 45% { -webkit-transform: rotate(-10deg); } - 75% { -webkit-transform: rotate(5deg); } - 100% { top: 0px; -webkit-transform: rotate(0); } - } - - @-moz-keyframes topbar-back { - 0% { top: 6px; -moz-transform: rotate(135deg); } - 45% { -moz-transform: rotate(-10deg); } - 75% { -moz-transform: rotate(5deg); } - 100% { top: 0px; -moz-transform: rotate(0); } - } -} - -@mixin bottombar-x-rotation(){ - @keyframes bottombar-x { - 0% {bottom: 0px; transform: rotate(0deg);} - 45% {bottom: 6px; transform: rotate(-145deg);} - 75% {transform: rotate(-130deg);} - 100% {transform: rotate(-135deg);} - } - @-webkit-keyframes bottombar-x { - 0% {bottom: 0px; -webkit-transform: rotate(0deg);} - 45% {bottom: 6px; -webkit-transform: rotate(-145deg);} - 75% {-webkit-transform: rotate(-130deg);} - 100% {-webkit-transform: rotate(-135deg);} - } - @-moz-keyframes bottombar-x { - 0% {bottom: 0px; -moz-transform: rotate(0deg);} - 45% {bottom: 6px; -moz-transform: rotate(-145deg);} - 75% {-moz-transform: rotate(-130deg);} - 100% {-moz-transform: rotate(-135deg);} - } -} - -@mixin bottombar-back-rotation(){ - @keyframes bottombar-back { - 0% { bottom: 6px;transform: rotate(-135deg);} - 45% { transform: rotate(10deg);} - 75% { transform: rotate(-5deg);} - 100% { bottom: 0px;transform: rotate(0);} - } - @-webkit-keyframes bottombar-back { - 0% {bottom: 6px;-webkit-transform: rotate(-135deg);} - 45% {-webkit-transform: rotate(10deg);} - 75% {-webkit-transform: rotate(-5deg);} - 100% {bottom: 0px;-webkit-transform: rotate(0);} - } - @-moz-keyframes bottombar-back { - 0% {bottom: 6px;-moz-transform: rotate(-135deg);} - 45% {-moz-transform: rotate(10deg);} - 75% {-moz-transform: rotate(-5deg);} - 100% {bottom: 0px;-moz-transform: rotate(0);} - } - -} - - diff --git a/frontend/assets/sass/nomad-ui/plugins/_animate.scss b/frontend/assets/sass/nomad-ui/plugins/_animate.scss deleted file mode 100644 index a019f044..00000000 --- a/frontend/assets/sass/nomad-ui/plugins/_animate.scss +++ /dev/null @@ -1,228 +0,0 @@ - - - - - - - - - - - - - - - - -// This file was modified by Creative Tim to keep only the animation that we need for Bootstrap Notify - - - - - - - - - - - - - - - -@charset "UTF-8"; - -/*! -Animate.css - http://daneden.me/animate -Licensed under the MIT license - http://opensource.org/licenses/MIT - -Copyright (c) 2015 Daniel Eden -*/ - -.animated { - -webkit-animation-duration: 1s; - animation-duration: 1s; - -webkit-animation-fill-mode: both; - animation-fill-mode: both; -} - -.animated.infinite { - -webkit-animation-iteration-count: infinite; - animation-iteration-count: infinite; -} - -.animated.hinge { - -webkit-animation-duration: 2s; - animation-duration: 2s; -} - -.animated.bounceIn, -.animated.bounceOut { - -webkit-animation-duration: .75s; - animation-duration: .75s; -} - -.animated.flipOutX, -.animated.flipOutY { - -webkit-animation-duration: .75s; - animation-duration: .75s; -} - -@-webkit-keyframes shake { - from, to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - 10%, 30%, 50%, 70%, 90% { - -webkit-transform: translate3d(-10px, 0, 0); - transform: translate3d(-10px, 0, 0); - } - - 20%, 40%, 60%, 80% { - -webkit-transform: translate3d(10px, 0, 0); - transform: translate3d(10px, 0, 0); - } -} - -@keyframes shake { - from, to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - 10%, 30%, 50%, 70%, 90% { - -webkit-transform: translate3d(-10px, 0, 0); - transform: translate3d(-10px, 0, 0); - } - - 20%, 40%, 60%, 80% { - -webkit-transform: translate3d(10px, 0, 0); - transform: translate3d(10px, 0, 0); - } -} - -.shake { - -webkit-animation-name: shake; - animation-name: shake; -} - - - -@-webkit-keyframes fadeInDown { - from { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes fadeInDown { - from { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -.fadeInDown { - -webkit-animation-name: fadeInDown; - animation-name: fadeInDown; -} - - -@-webkit-keyframes fadeOut { - from { - opacity: 1; - } - - to { - opacity: 0; - } -} - -@keyframes fadeOut { - from { - opacity: 1; - } - - to { - opacity: 0; - } -} - -.fadeOut { - -webkit-animation-name: fadeOut; - animation-name: fadeOut; -} - -@-webkit-keyframes fadeOutDown { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } -} - -@keyframes fadeOutDown { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } -} - -.fadeOutDown { - -webkit-animation-name: fadeOutDown; - animation-name: fadeOutDown; -} - -@-webkit-keyframes fadeOutUp { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } -} - -@keyframes fadeOutUp { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } -} - -.fadeOutUp { - -webkit-animation-name: fadeOutUp; - animation-name: fadeOutUp; -} - diff --git a/frontend/assets/sass/nomad-ui/plugins/_bootstrap-select.scss b/frontend/assets/sass/nomad-ui/plugins/_bootstrap-select.scss deleted file mode 100644 index 55b1d97c..00000000 --- a/frontend/assets/sass/nomad-ui/plugins/_bootstrap-select.scss +++ /dev/null @@ -1,308 +0,0 @@ -/*! - * Bootstrap-select v1.8.1 (http://silviomoreto.github.io/bootstrap-select) - * - * Copyright 2013-2015 bootstrap-select - * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE) - */ - -.bootstrap-select { - width: 220px \0; - /*IE9 and below*/ -} -.bootstrap-select > .dropdown-toggle { - width: 100%; - padding-right: 25px; - z-index: 1; -} -.bootstrap-select > select { - position: absolute; - bottom: 0; - left: 50%; - width: 0.11px; - height: 100%; - opacity: 0; - border: none; -} -.bootstrap-select > select.mobile-device { - position: absolute !important; - top: 0; - left: 0; - display: block !important; - width: 100%; - height: 100% !important; - opacity: 0; - z-index: 2; -} -.has-error .bootstrap-select .dropdown-toggle, -.error .bootstrap-select .dropdown-toggle { - border-color: #b94a48; -} -.bootstrap-select.fit-width { - width: auto !important; -} -.bootstrap-select:not([class*="col-"]):not([class*="form-control"]):not(.input-group-btn) { - width: 100%; -} - -.bootstrap-select.form-control { - margin-bottom: 0; - padding: 0; - border: none; -} -.bootstrap-select.form-control:not([class*="col-"]) { - width: 100%; -} -.bootstrap-select.form-control.input-group-btn { - z-index: auto; -} -.bootstrap-select.btn-group:not(.input-group-btn), -.bootstrap-select.btn-group[class*="col-"] { - float: none; - display: inline-block; - margin-left: 0; -} -.bootstrap-select.btn-group.dropdown-menu-right, -.bootstrap-select.btn-group[class*="col-"].dropdown-menu-right, -.row .bootstrap-select.btn-group[class*="col-"].dropdown-menu-right { - float: right; -} -.form-inline .bootstrap-select.btn-group, -.form-horizontal .bootstrap-select.btn-group, -.form-group .bootstrap-select.btn-group { - margin-bottom: 0; -} -.form-group-lg .bootstrap-select.btn-group.form-control, -.form-group-sm .bootstrap-select.btn-group.form-control { - padding: 0; -} -.form-inline .bootstrap-select.btn-group .form-control { - width: 100%; -} -.bootstrap-select.btn-group.disabled, -.bootstrap-select.btn-group > .disabled { - cursor: not-allowed; -} -.bootstrap-select.btn-group.disabled:focus, -.bootstrap-select.btn-group > .disabled:focus { - outline: none !important; -} -.bootstrap-select.btn-group.bs-container { - position: absolute; -} -.bootstrap-select.btn-group.bs-container .dropdown-menu { - z-index: 1060; -} -.bootstrap-select.btn-group .dropdown-toggle .filter-option { - display: inline-block; - overflow: hidden; - width: 100%; - text-align: left; -} -.bootstrap-select.btn-group .dropdown-toggle .caret { - position: absolute; - top: 50%; - right: 12px; - margin-top: -2px; - vertical-align: middle; -} -.bootstrap-select.btn-group[class*="col-"] .dropdown-toggle { - width: 100%; -} -.bootstrap-select.btn-group .dropdown-menu { - min-width: 100%; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -.bootstrap-select.btn-group .dropdown-menu.inner { - position: static; - float: none; - border: 0; - padding: 0; - margin: 0; - border-radius: 0; - -webkit-box-shadow: none; - box-shadow: none; - -ms-overflow-style: scrollbar; // fix for IE issues when we are on Windows and have Perfect Scrollbar ON -} -.bootstrap-select.btn-group .dropdown-menu li { - position: relative; -} -.bootstrap-select.btn-group .dropdown-menu li.active small { - color: #fff; -} -.bootstrap-select.btn-group .dropdown-menu li.disabled a { - cursor: not-allowed; -} -.bootstrap-select.btn-group .dropdown-menu li a { - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} -.bootstrap-select.btn-group .dropdown-menu li a.opt { - position: relative; - padding-left: 2.25em; -} -.bootstrap-select.btn-group .dropdown-menu li a span.check-mark { - display: none; -} -.bootstrap-select.btn-group .dropdown-menu li a span.text { - display: inline-block; -} -.bootstrap-select.btn-group .dropdown-menu li small { - padding-left: 0.5em; -} -.bootstrap-select.btn-group .dropdown-menu .notify { - position: absolute; - bottom: 5px; - width: 96%; - margin: 0 2%; - min-height: 26px; - padding: 3px 5px; - background: #f5f5f5; - border: 1px solid #e3e3e3; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); - pointer-events: none; - opacity: 0.9; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -.bootstrap-select.btn-group .no-results { - padding: 3px; - background: #f5f5f5; - margin: 0 5px; - white-space: nowrap; -} -.bootstrap-select.btn-group.fit-width .dropdown-toggle .filter-option { - position: static; -} -.bootstrap-select.btn-group.fit-width .dropdown-toggle .caret { - position: static; - top: auto; - margin-top: -1px; -} -.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a span.check-mark { - position: absolute; - display: inline-block; - right: 15px; - margin-top: 2px; -} -.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text { - margin-right: 34px; -} -.bootstrap-select.show-menu-arrow.open > .dropdown-toggle { - z-index: 1061; -} -.bootstrap-select.show-menu-arrow .dropdown-toggle:before { - content: ''; - border-left: 7px solid transparent; - border-right: 7px solid transparent; - border-bottom: 7px solid rgba(204, 204, 204, 0.2); - position: absolute; - bottom: -4px; - left: 9px; - display: none; -} -.bootstrap-select.show-menu-arrow .dropdown-toggle:after { - content: ''; - border-left: 6px solid transparent; - border-right: 6px solid transparent; - border-bottom: 6px solid white; - position: absolute; - bottom: -4px; - left: 10px; - display: none; -} -.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:before { - bottom: auto; - top: -3px; - border-top: 7px solid rgba(204, 204, 204, 0.2); - border-bottom: 0; -} -.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:after { - bottom: auto; - top: -3px; - border-top: 6px solid white; - border-bottom: 0; -} -.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:before { - right: 12px; - left: auto; -} -.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:after { - right: 13px; - left: auto; -} -.bootstrap-select.show-menu-arrow.open > .dropdown-toggle:before, -.bootstrap-select.show-menu-arrow.open > .dropdown-toggle:after { - display: block; -} -.bs-searchbox, -.bs-actionsbox, -.bs-donebutton { - padding: 8px 8px; -} -.bs-actionsbox { - width: 100%; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -.bs-actionsbox .btn-group button { - width: 50%; -} -.bs-donebutton { - float: left; - width: 100%; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -.bs-donebutton .btn-group button { - width: 100%; -} -.bs-searchbox + .bs-actionsbox { - padding: 0 8px 4px; -} -.bs-searchbox .form-control { - margin-bottom: 0; - width: 100%; - float: none; -} - -.bootstrap-select{ - .dropdown-menu{ - border-radius: $border-radius-bottom; - @include box-shadow(none); - @include transform-origin($select-coordinates); - @include transform-scale(1); - @include transition($fast-transition-time, $transition-linear); - margin-top: -20px; - } - - &.open .dropdown-menu{ - margin-top: -1px; - } - - &.dropup .dropdown-menu{ - border-radius: $border-radius-top; - margin-bottom: -20px; - } - - &.dropup.open .dropdown-menu{ - margin-bottom: -1px; - } -} - -.btn-group.bootstrap-select .dropdown-menu{ - min-width: 100%; -} - -.bootstrap-select .dropdown-menu > li:first-child > a{ - border-radius: 0; - border-bottom: 0 none; -} diff --git a/frontend/assets/sass/nomad-ui/plugins/_bootstrap-table.scss b/frontend/assets/sass/nomad-ui/plugins/_bootstrap-table.scss deleted file mode 100644 index 4859b7b5..00000000 --- a/frontend/assets/sass/nomad-ui/plugins/_bootstrap-table.scss +++ /dev/null @@ -1,328 +0,0 @@ -/** - * @author zhixin wen - * version: 1.8.1 - * https://github.com/wenzhixin/bootstrap-table/ - */ - -.bootstrap-table .table { - margin-bottom: 0 !important; - border-bottom: 1px solid #dddddd; - border-collapse: collapse !important; - border-radius: 1px; -} - -.bootstrap-table .table, -.bootstrap-table .table > tbody > tr > th, -.bootstrap-table .table > tfoot > tr > th, -.bootstrap-table .table > thead > tr > td, -.bootstrap-table .table > tbody > tr > td, -.bootstrap-table .table > tfoot > tr > td { - padding: 8px !important; -} - -.bootstrap-table .table > tbody > .selected{ - background-color: $light-blue; -} -.bootstrap-table .table.table-no-bordered > thead > tr > th, -.bootstrap-table .table.table-no-bordered > tbody > tr > td { - border-right: 2px solid transparent; -} - -.fixed-table-container { - position: relative; - clear: both; -} - -.fixed-table-container.table-no-bordered { - border: 1px solid transparent; -} - -.fixed-table-footer, -.fixed-table-header { - overflow: hidden; -} - -.fixed-table-footer { - border-top: 1px solid #dddddd; -} - -.fixed-table-body { - height: 100%; - overflow: auto; -} - -.fixed-table-container table { - width: 100%; -} - -.fixed-table-container thead th { - height: 0; - padding: 0; - margin: 0; -} - -.fixed-table-container thead th:first-child { - border-left: none; -} - -.fixed-table-container thead th .th-inner { - padding: 0 8px; - line-height: 24px; - vertical-align: top; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.fixed-table-container thead th .sortable { - cursor: pointer; - background-repeat: no-repeat; - padding-right: 30px; -} - -.fixed-table-container thead th .both { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAkElEQVQoz7X QMQ5AQBCF4dWQSJxC5wwax1Cq1e7BAdxD5SL+Tq/QCM1oNiJidwox0355mXnG/DrEtIQ6azioNZQxI0ykPhTQIwhCR+BmBYtlK7kLJYwWCcJA9M4qdrZrd8pPjZWPtOqdRQy320YSV17OatFC4euts6z39GYMKRPCTKY9UnPQ6P+GtMRfGtPnBCiqhAeJPmkqAAAAAElFTkSuQmCC'); - background-position: right 2px; -} - -.fixed-table-container thead th .asc { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAG2YAABzjgAA+swAAIT6AAB5gQAA/RMAADBtAAASKQ0eJk4AAACASURBVHja7NKhDcJQFIbRV1MSEqaoYwYMYyARR6HZowzAHqguUolHYEgxD9MmTYPpA1JEb/KZK476Q4wxfKvwc6x/WKJE3v+nYkc8cfgIwxpXRNQokjBkOLdQ1wlZCrbFbYDdsRmFYYVqAHVdsBiD7dHg8aYGu2l2NmMz9s/YawDpU8qkYQTHqgAAAABJRU5ErkJggg=='); - background-position: right 5px; -} - -.fixed-table-container thead th .desc { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAG2YAABzjgAA+swAAIT6AAB5gQAA/RMAADBtAAASKQ0eJk4AAACFSURBVHja7NKhDcJQFIbRWwMJCVPgmKGGMZCIo9DsAQOwRxWLIPEIDCnmYR4JaSp4DYKQis/8NznqRkopvlWM2Ij9BYY1Wtx7arEpwaZokHo6Yf4xFhGBGrcOdMUqIqIUq3DoYEdUxVgGFzhn6ILl61aMZXCLB3bv+1Bsgj1mg7CfeNrnAMXSyqQtsCNeAAAAAElFTkSuQmCC'); - background-position: right 0px; -} - - -.fixed-table-container th.detail { - width: 30px; -} - -.fixed-table-container tbody tr:first-child td { - border-top: none; -} - -.fixed-table-container tbody td:first-child { - border-left: none; -} - -/* the same color with .active */ -.fixed-table-container tbody .selected td { - background-color: rgba(245, 245, 245, 0.34); -} - -.fixed-table-container .bs-checkbox { - text-align: center; -} - -.fixed-table-container .bs-checkbox .th-inner { - padding: 8px 0; -} - -.fixed-table-container input[type="radio"], -.fixed-table-container input[type="checkbox"] { - margin: 0 auto !important; - cursor: pointer; -} - -.fixed-table-container .no-records-found { - text-align: center; - background-color: #FFFFFF !important; - height: 340px; - border-radius: 10px; - width: 100%; - vertical-align: middle; -} -.fixed-table-container .no-records-found td{ - font-weight: $font-weight-light; - font-size: $font-size-h4; -} -.fixed-table-pagination div.pagination, -.fixed-table-pagination .pagination-detail { - margin-top: 10px; - margin-bottom: 10px; -} - -.fixed-table-pagination div.pagination .pagination { - margin: 0; -} - -.fixed-table-pagination .pagination a { - padding: 6px 12px; - line-height: 1.428571429; -} - -.fixed-table-pagination .pagination-info { - line-height: 34px; - margin-right: 5px; -} - -.fixed-table-pagination .btn-group { - position: relative; - display: inline-block; - vertical-align: middle; -} - -.fixed-table-pagination .page-list { - display: inline-block; -} - -.fixed-table-toolbar{ - padding: 5px 15px; -} - -.fixed-table-toolbar .columns-left { - margin-right: 5px; -} - -.fixed-table-toolbar .columns-right { - margin-left: 5px; -} - -.fixed-table-toolbar .columns .btn{ - margin: 0 2px; - border-radius: $btn-round-radius; -} -.fixed-table-toolbar .columns label { - display: block; - padding: 10px 20px; - border-bottom: 1px solid #eee; - clear: both; - margin-bottom: 0; - font-weight: normal; - line-height: 1.428571429; -} -.fixed-table-toolbar .columns li:last-child label{ - border-bottom: none; -} - -.fixed-table-toolbar .bars, -.fixed-table-toolbar .search, -.fixed-table-toolbar .columns { - position: relative; - margin-top: 10px; - margin-bottom: 10px; - line-height: 34px; -} - -.fixed-table-pagination li.disabled a { - pointer-events: none; - cursor: default; -} - -.fixed-table-loading { - display: none; - position: absolute; - top: 42px; - right: 0; - bottom: 0; - left: 0; - z-index: 99; - background-color: #fff; - text-align: center; -} - -.fixed-table-body .card-view .title { - font-weight: bold; - display: inline-block; - min-width: 30%; - text-align: left !important; -} - -/* support bootstrap 2 */ -.fixed-table-body thead th .th-inner { - box-sizing: border-box; -} - -.table th, .table td { - vertical-align: middle; - box-sizing: border-box; -} - -.fixed-table-toolbar .btn-group > .btn-group { - display: inline-block; - margin-left: -1px !important; -} - -.fixed-table-toolbar .dropdown-menu label{ - cursor: pointer; -} - -.fixed-table-toolbar .btn-group > .btn-group > .btn { - border-radius: 0; -} - -.fixed-table-toolbar .btn-group > .btn-group:first-child > .btn { - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; -} - -.fixed-table-toolbar .btn-group > .btn-group:last-child > .btn { - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; -} - -/* support bootstrap 3 */ -.bootstrap-table .table thead > tr > th { - padding: 0; - margin: 0; -} - -.pull-right .dropdown-menu { - right: 0; - left: auto; -} - -/* calculate scrollbar width */ -p.fixed-table-scroll-inner { - width: 100%; - height: 200px; -} - -div.fixed-table-scroll-outer { - top: 0; - left: 0; - visibility: hidden; - width: 200px; - height: 150px; - overflow: hidden; -} - - -.bootstrap-table{ - .fixed-table-pagination{ - margin: 0 10px; - - &:after{ - display: table; - content: ""; - clear: both; - } - - .page-list{ - .btn{ - border-radius: $btn-round-radius; - } - .btn-group{ - margin-right: 5px; - } - } - div.pagination, - .pagination-detail{ - margin-top: 15px; - margin-bottom: 15px; - } - } - - .table{ - &.table-striped > thead > tr > td, - &.table-striped > tbody > tr >td, - &.table-striped > tfoot > tr >td{ - border: none; - } - - } - -} diff --git a/frontend/assets/sass/nomad-ui/plugins/_chartist.scss b/frontend/assets/sass/nomad-ui/plugins/_chartist.scss deleted file mode 100644 index ec47902c..00000000 --- a/frontend/assets/sass/nomad-ui/plugins/_chartist.scss +++ /dev/null @@ -1,247 +0,0 @@ -@mixin ct-responsive-svg-container($width: 100%, $ratio: $ct-container-ratio) { - display: block; - position: relative; - width: $width; - - &:before { - display: block; - float: left; - content: ""; - width: 0; - height: 0; - padding-bottom: $ratio * 100%; - } - - &:after { - content: ""; - display: table; - clear: both; - } - - > svg { - display: block; - position: absolute; - top: 0; - left: 0; - } -} - -@mixin ct-align-justify($ct-text-align: $ct-text-align, $ct-text-justify: $ct-text-justify) { - -webkit-box-align: $ct-text-align; - -webkit-align-items: $ct-text-align; - -ms-flex-align: $ct-text-align; - align-items: $ct-text-align; - -webkit-box-pack: $ct-text-justify; - -webkit-justify-content: $ct-text-justify; - -ms-flex-pack: $ct-text-justify; - justify-content: $ct-text-justify; - // Fallback to text-align for non-flex browsers - @if($ct-text-justify == 'flex-start') { - text-align: left; - } @else if ($ct-text-justify == 'flex-end') { - text-align: right; - } @else { - text-align: center; - } -} - -@mixin ct-flex() { - // Fallback to block - display: block; - display: -webkit-box; - display: -moz-box; - display: -ms-flexbox; - display: -webkit-flex; - display: flex; -} - -@mixin ct-chart-label($ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-text-line-height: $ct-text-line-height) { - fill: $ct-text-color; - color: $ct-text-color; - font-size: $ct-text-size; - line-height: $ct-text-line-height; -} - -@mixin ct-chart-grid($ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray) { - stroke: $ct-grid-color; - stroke-width: $ct-grid-width; - - @if ($ct-grid-dasharray) { - stroke-dasharray: $ct-grid-dasharray; - } -} - -@mixin ct-chart-point($ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape) { - stroke-width: $ct-point-size; - stroke-linecap: $ct-point-shape; -} - -@mixin ct-chart-line($ct-line-width: $ct-line-width, $ct-line-dasharray: $ct-line-dasharray) { - fill: none; - stroke-width: $ct-line-width; - - @if ($ct-line-dasharray) { - stroke-dasharray: $ct-line-dasharray; - } -} - -@mixin ct-chart-area($ct-area-opacity: $ct-area-opacity) { - stroke: none; - fill-opacity: $ct-area-opacity; -} - -@mixin ct-chart-bar($ct-bar-width: $ct-bar-width) { - fill: none; - stroke-width: $ct-bar-width; -} - -@mixin ct-chart-donut($ct-donut-width: $ct-donut-width) { - fill: none; - stroke-width: $ct-donut-width; -} - -@mixin ct-chart-series-color($color) { - .#{$ct-class-point}, .#{$ct-class-line}, .#{$ct-class-bar}, .#{$ct-class-slice-donut} { - stroke: $color; - } - - .#{$ct-class-slice-pie}, .#{$ct-class-area} { - fill: $color; - } -} - -@mixin ct-chart($ct-container-ratio: $ct-container-ratio, $ct-text-color: $ct-text-color, $ct-text-size: $ct-text-size, $ct-grid-color: $ct-grid-color, $ct-grid-width: $ct-grid-width, $ct-grid-dasharray: $ct-grid-dasharray, $ct-point-size: $ct-point-size, $ct-point-shape: $ct-point-shape, $ct-line-width: $ct-line-width, $ct-bar-width: $ct-bar-width, $ct-donut-width: $ct-donut-width, $ct-series-names: $ct-series-names, $ct-series-colors: $ct-series-colors) { - - .#{$ct-class-label} { - @include ct-chart-label($ct-text-color, $ct-text-size); - } - - .#{$ct-class-chart-line} .#{$ct-class-label}, - .#{$ct-class-chart-bar} .#{$ct-class-label} { - @include ct-flex(); - } - - .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} { - @include ct-align-justify(flex-end, flex-start); - // Fallback for browsers that don't support foreignObjects - text-anchor: start; - } - - .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-end} { - @include ct-align-justify(flex-start, flex-start); - // Fallback for browsers that don't support foreignObjects - text-anchor: start; - } - - .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-start} { - @include ct-align-justify(flex-end, flex-end); - // Fallback for browsers that don't support foreignObjects - text-anchor: end; - } - - .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-end} { - @include ct-align-justify(flex-end, flex-start); - // Fallback for browsers that don't support foreignObjects - text-anchor: start; - } - - .#{$ct-class-chart-bar} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} { - @include ct-align-justify(flex-end, center); - // Fallback for browsers that don't support foreignObjects - text-anchor: start; - } - - .#{$ct-class-chart-bar} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-end} { - @include ct-align-justify(flex-start, center); - // Fallback for browsers that don't support foreignObjects - text-anchor: start; - } - - .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} { - @include ct-align-justify(flex-end, flex-start); - // Fallback for browsers that don't support foreignObjects - text-anchor: start; - } - - .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-end} { - @include ct-align-justify(flex-start, flex-start); - // Fallback for browsers that don't support foreignObjects - text-anchor: start; - } - - .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-start} { - //@include ct-chart-label($ct-text-color, $ct-text-size, center, $ct-vertical-text-justify); - @include ct-align-justify(center, flex-end); - // Fallback for browsers that don't support foreignObjects - text-anchor: end; - } - - .#{$ct-class-chart-bar}.#{$ct-class-horizontal-bars} .#{$ct-class-label}.#{$ct-class-vertical}.#{$ct-class-end} { - @include ct-align-justify(center, flex-start); - // Fallback for browsers that don't support foreignObjects - text-anchor: end; - } - - .#{$ct-class-grid} { - @include ct-chart-grid($ct-grid-color, $ct-grid-width, $ct-grid-dasharray); - } - - .#{$ct-class-point} { - @include ct-chart-point($ct-point-size, $ct-point-shape); - } - - .#{$ct-class-line} { - @include ct-chart-line($ct-line-width); - } - - .#{$ct-class-area} { - @include ct-chart-area(); - } - - .#{$ct-class-bar} { - @include ct-chart-bar($ct-bar-width); - } - - .#{$ct-class-slice-donut} { - @include ct-chart-donut($ct-donut-width); - } - - @if $ct-include-colored-series { - @for $i from 0 to length($ct-series-names) { - .#{$ct-class-series}-#{nth($ct-series-names, $i + 1)} { - $color: nth($ct-series-colors, $i + 1); - - @include ct-chart-series-color($color); - } - } - } -} - -@if $ct-include-classes { - @include ct-chart(); - - @if $ct-include-alternative-responsive-containers { - @for $i from 0 to length($ct-scales-names) { - .#{nth($ct-scales-names, $i + 1)} { - @include ct-responsive-svg-container($ratio: nth($ct-scales, $i + 1)); - } - } - } -} - - -.ct-blue{ - stroke: $color-blue !important; -} -.ct-azure{ - stroke: $color-azure !important; -} -.ct-green{ - stroke: $color-green !important; -} -.ct-orange{ - stroke: $color-orange !important; -} -.ct-red{ - stroke: $color-red !important; -} \ No newline at end of file diff --git a/frontend/assets/sass/nomad-ui/plugins/_datatable.scss b/frontend/assets/sass/nomad-ui/plugins/_datatable.scss deleted file mode 100644 index 4859b7b5..00000000 --- a/frontend/assets/sass/nomad-ui/plugins/_datatable.scss +++ /dev/null @@ -1,328 +0,0 @@ -/** - * @author zhixin wen - * version: 1.8.1 - * https://github.com/wenzhixin/bootstrap-table/ - */ - -.bootstrap-table .table { - margin-bottom: 0 !important; - border-bottom: 1px solid #dddddd; - border-collapse: collapse !important; - border-radius: 1px; -} - -.bootstrap-table .table, -.bootstrap-table .table > tbody > tr > th, -.bootstrap-table .table > tfoot > tr > th, -.bootstrap-table .table > thead > tr > td, -.bootstrap-table .table > tbody > tr > td, -.bootstrap-table .table > tfoot > tr > td { - padding: 8px !important; -} - -.bootstrap-table .table > tbody > .selected{ - background-color: $light-blue; -} -.bootstrap-table .table.table-no-bordered > thead > tr > th, -.bootstrap-table .table.table-no-bordered > tbody > tr > td { - border-right: 2px solid transparent; -} - -.fixed-table-container { - position: relative; - clear: both; -} - -.fixed-table-container.table-no-bordered { - border: 1px solid transparent; -} - -.fixed-table-footer, -.fixed-table-header { - overflow: hidden; -} - -.fixed-table-footer { - border-top: 1px solid #dddddd; -} - -.fixed-table-body { - height: 100%; - overflow: auto; -} - -.fixed-table-container table { - width: 100%; -} - -.fixed-table-container thead th { - height: 0; - padding: 0; - margin: 0; -} - -.fixed-table-container thead th:first-child { - border-left: none; -} - -.fixed-table-container thead th .th-inner { - padding: 0 8px; - line-height: 24px; - vertical-align: top; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.fixed-table-container thead th .sortable { - cursor: pointer; - background-repeat: no-repeat; - padding-right: 30px; -} - -.fixed-table-container thead th .both { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAkElEQVQoz7X QMQ5AQBCF4dWQSJxC5wwax1Cq1e7BAdxD5SL+Tq/QCM1oNiJidwox0355mXnG/DrEtIQ6azioNZQxI0ykPhTQIwhCR+BmBYtlK7kLJYwWCcJA9M4qdrZrd8pPjZWPtOqdRQy320YSV17OatFC4euts6z39GYMKRPCTKY9UnPQ6P+GtMRfGtPnBCiqhAeJPmkqAAAAAElFTkSuQmCC'); - background-position: right 2px; -} - -.fixed-table-container thead th .asc { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAG2YAABzjgAA+swAAIT6AAB5gQAA/RMAADBtAAASKQ0eJk4AAACASURBVHja7NKhDcJQFIbRV1MSEqaoYwYMYyARR6HZowzAHqguUolHYEgxD9MmTYPpA1JEb/KZK476Q4wxfKvwc6x/WKJE3v+nYkc8cfgIwxpXRNQokjBkOLdQ1wlZCrbFbYDdsRmFYYVqAHVdsBiD7dHg8aYGu2l2NmMz9s/YawDpU8qkYQTHqgAAAABJRU5ErkJggg=='); - background-position: right 5px; -} - -.fixed-table-container thead th .desc { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAG2YAABzjgAA+swAAIT6AAB5gQAA/RMAADBtAAASKQ0eJk4AAACFSURBVHja7NKhDcJQFIbRWwMJCVPgmKGGMZCIo9DsAQOwRxWLIPEIDCnmYR4JaSp4DYKQis/8NznqRkopvlWM2Ij9BYY1Wtx7arEpwaZokHo6Yf4xFhGBGrcOdMUqIqIUq3DoYEdUxVgGFzhn6ILl61aMZXCLB3bv+1Bsgj1mg7CfeNrnAMXSyqQtsCNeAAAAAElFTkSuQmCC'); - background-position: right 0px; -} - - -.fixed-table-container th.detail { - width: 30px; -} - -.fixed-table-container tbody tr:first-child td { - border-top: none; -} - -.fixed-table-container tbody td:first-child { - border-left: none; -} - -/* the same color with .active */ -.fixed-table-container tbody .selected td { - background-color: rgba(245, 245, 245, 0.34); -} - -.fixed-table-container .bs-checkbox { - text-align: center; -} - -.fixed-table-container .bs-checkbox .th-inner { - padding: 8px 0; -} - -.fixed-table-container input[type="radio"], -.fixed-table-container input[type="checkbox"] { - margin: 0 auto !important; - cursor: pointer; -} - -.fixed-table-container .no-records-found { - text-align: center; - background-color: #FFFFFF !important; - height: 340px; - border-radius: 10px; - width: 100%; - vertical-align: middle; -} -.fixed-table-container .no-records-found td{ - font-weight: $font-weight-light; - font-size: $font-size-h4; -} -.fixed-table-pagination div.pagination, -.fixed-table-pagination .pagination-detail { - margin-top: 10px; - margin-bottom: 10px; -} - -.fixed-table-pagination div.pagination .pagination { - margin: 0; -} - -.fixed-table-pagination .pagination a { - padding: 6px 12px; - line-height: 1.428571429; -} - -.fixed-table-pagination .pagination-info { - line-height: 34px; - margin-right: 5px; -} - -.fixed-table-pagination .btn-group { - position: relative; - display: inline-block; - vertical-align: middle; -} - -.fixed-table-pagination .page-list { - display: inline-block; -} - -.fixed-table-toolbar{ - padding: 5px 15px; -} - -.fixed-table-toolbar .columns-left { - margin-right: 5px; -} - -.fixed-table-toolbar .columns-right { - margin-left: 5px; -} - -.fixed-table-toolbar .columns .btn{ - margin: 0 2px; - border-radius: $btn-round-radius; -} -.fixed-table-toolbar .columns label { - display: block; - padding: 10px 20px; - border-bottom: 1px solid #eee; - clear: both; - margin-bottom: 0; - font-weight: normal; - line-height: 1.428571429; -} -.fixed-table-toolbar .columns li:last-child label{ - border-bottom: none; -} - -.fixed-table-toolbar .bars, -.fixed-table-toolbar .search, -.fixed-table-toolbar .columns { - position: relative; - margin-top: 10px; - margin-bottom: 10px; - line-height: 34px; -} - -.fixed-table-pagination li.disabled a { - pointer-events: none; - cursor: default; -} - -.fixed-table-loading { - display: none; - position: absolute; - top: 42px; - right: 0; - bottom: 0; - left: 0; - z-index: 99; - background-color: #fff; - text-align: center; -} - -.fixed-table-body .card-view .title { - font-weight: bold; - display: inline-block; - min-width: 30%; - text-align: left !important; -} - -/* support bootstrap 2 */ -.fixed-table-body thead th .th-inner { - box-sizing: border-box; -} - -.table th, .table td { - vertical-align: middle; - box-sizing: border-box; -} - -.fixed-table-toolbar .btn-group > .btn-group { - display: inline-block; - margin-left: -1px !important; -} - -.fixed-table-toolbar .dropdown-menu label{ - cursor: pointer; -} - -.fixed-table-toolbar .btn-group > .btn-group > .btn { - border-radius: 0; -} - -.fixed-table-toolbar .btn-group > .btn-group:first-child > .btn { - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; -} - -.fixed-table-toolbar .btn-group > .btn-group:last-child > .btn { - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; -} - -/* support bootstrap 3 */ -.bootstrap-table .table thead > tr > th { - padding: 0; - margin: 0; -} - -.pull-right .dropdown-menu { - right: 0; - left: auto; -} - -/* calculate scrollbar width */ -p.fixed-table-scroll-inner { - width: 100%; - height: 200px; -} - -div.fixed-table-scroll-outer { - top: 0; - left: 0; - visibility: hidden; - width: 200px; - height: 150px; - overflow: hidden; -} - - -.bootstrap-table{ - .fixed-table-pagination{ - margin: 0 10px; - - &:after{ - display: table; - content: ""; - clear: both; - } - - .page-list{ - .btn{ - border-radius: $btn-round-radius; - } - .btn-group{ - margin-right: 5px; - } - } - div.pagination, - .pagination-detail{ - margin-top: 15px; - margin-bottom: 15px; - } - } - - .table{ - &.table-striped > thead > tr > td, - &.table-striped > tbody > tr >td, - &.table-striped > tfoot > tr >td{ - border: none; - } - - } - -} diff --git a/frontend/assets/sass/nomad-ui/plugins/_datatables.net.scss b/frontend/assets/sass/nomad-ui/plugins/_datatables.net.scss deleted file mode 100644 index 388e6f68..00000000 --- a/frontend/assets/sass/nomad-ui/plugins/_datatables.net.scss +++ /dev/null @@ -1,513 +0,0 @@ -table.dataTable { - clear: both; - margin-top: 6px !important; - margin-bottom: 6px !important; - max-width: none !important; - border-collapse: separate !important; -} -table.dataTable td, -table.dataTable th { - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; -} -table.dataTable td.dataTables_empty, -table.dataTable th.dataTables_empty { - text-align: center; -} -table.dataTable.nowrap th, -table.dataTable.nowrap td { - white-space: nowrap; -} - -div.dataTables_wrapper div.dataTables_length label { - font-weight: normal; - text-align: left; - white-space: nowrap; -} -div.dataTables_wrapper div.dataTables_length select { - width: 75px; - display: inline-block; -} -div.dataTables_wrapper div.dataTables_filter { - text-align: right; -} -div.dataTables_wrapper div.dataTables_filter label { - font-weight: normal; - white-space: nowrap; - text-align: left; -} -div.dataTables_wrapper div.dataTables_filter input { - margin-left: 0.5em; - display: inline-block; - width: auto; -} -div.dataTables_wrapper div.dataTables_info { - padding-top: 8px; - white-space: nowrap; -} -div.dataTables_wrapper div.dataTables_paginate { - margin: 0; - white-space: nowrap; - text-align: right; -} -div.dataTables_wrapper div.dataTables_paginate ul.pagination { - margin: 2px 0; - white-space: nowrap; -} -div.dataTables_wrapper div.dataTables_processing { - position: absolute; - top: 50%; - left: 50%; - width: 200px; - margin-left: -100px; - margin-top: -26px; - text-align: center; - padding: 1em 0; -} - -table.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting, -table.dataTable thead > tr > td.sorting_asc, -table.dataTable thead > tr > td.sorting_desc, -table.dataTable thead > tr > td.sorting { - padding-right: 30px; -} -table.dataTable thead > tr > th:active, -table.dataTable thead > tr > td:active { - outline: none; -} -table.dataTable thead .sorting, -table.dataTable thead .sorting_asc, -table.dataTable thead .sorting_desc, -table.dataTable thead .sorting_asc_disabled, -table.dataTable thead .sorting_desc_disabled { - cursor: pointer; - position: relative; -} -table.dataTable thead .sorting:after, -table.dataTable thead .sorting_asc:after, -table.dataTable thead .sorting_desc:after, -table.dataTable thead .sorting_asc_disabled:after, -table.dataTable thead .sorting_desc_disabled:after { - position: absolute; - bottom: 8px; - right: 8px; - display: block; - font-family: 'Glyphicons Halflings'; - opacity: 0.5; -} -table.dataTable thead .sorting:after { - opacity: 0.2; - content: "\e150"; - /* sort */ -} -table.dataTable thead .sorting_asc:after { - content: "\e155"; - /* sort-by-attributes */ -} -table.dataTable thead .sorting_desc:after { - content: "\e156"; - /* sort-by-attributes-alt */ -} -table.dataTable thead .sorting_asc_disabled:after, -table.dataTable thead .sorting_desc_disabled:after { - color: #eee; -} - -div.dataTables_scrollHead table.dataTable { - margin-bottom: 0 !important; -} - -div.dataTables_scrollBody table { - border-top: none; - margin-top: 0 !important; - margin-bottom: 0 !important; -} -div.dataTables_scrollBody table thead .sorting:after, -div.dataTables_scrollBody table thead .sorting_asc:after, -div.dataTables_scrollBody table thead .sorting_desc:after { - display: none; -} -div.dataTables_scrollBody table tbody tr:first-child th, -div.dataTables_scrollBody table tbody tr:first-child td { - border-top: none; -} - -div.dataTables_scrollFoot table { - margin-top: 0 !important; - border-top: none; -} - -@media screen and (max-width: 767px) { - div.dataTables_wrapper div.dataTables_length, - div.dataTables_wrapper div.dataTables_filter, - div.dataTables_wrapper div.dataTables_info, - div.dataTables_wrapper div.dataTables_paginate { - text-align: center; - } -} -table.dataTable.table-condensed > thead > tr > th { - padding-right: 20px; -} -table.dataTable.table-condensed .sorting:after, -table.dataTable.table-condensed .sorting_asc:after, -table.dataTable.table-condensed .sorting_desc:after { - top: 6px; - right: 6px; -} - -table.table-bordered.dataTable th, -table.table-bordered.dataTable td { - border-left-width: 0; -} -table.table-bordered.dataTable th:last-child, table.table-bordered.dataTable th:last-child, -table.table-bordered.dataTable td:last-child, -table.table-bordered.dataTable td:last-child { - border-right-width: 0; -} -table.table-bordered.dataTable tbody th, -table.table-bordered.dataTable tbody td { - border-bottom-width: 0; -} - -div.dataTables_scrollHead table.table-bordered { - border-bottom-width: 0; -} - -div.table-responsive > div.dataTables_wrapper > div.row { - margin: 0; -} -div.table-responsive > div.dataTables_wrapper > div.row > div[class^="col-"]:first-child { - padding-left: 0; -} -div.table-responsive > div.dataTables_wrapper > div.row > div[class^="col-"]:last-child { - padding-right: 0; -} - - -table.dataTable{ - - .btn-simple.btn-icon{ - padding: 3px; - } - - thead{ - .sorting, - .sorting_asc, - .sorting_desc, - .sorting_asc_disabled, - .sorting_desc_disabled{ - - &:after{ - position: relative; - display: inline-block; - bottom: 0px; - right: -7px; - font-family: 'FontAwesome'; - opacity: 0.8; - } - - } - - .disabled-sorting.sorting, - .disabled-sorting.sorting_asc, - .disabled-sorting.sorting_desc, - .disabled-sorting.sorting_asc_disabled, - .disabled-sorting.sorting_desc_disabled{ - &:after{ - display: none; - } - - } - - .sorting{ - &:after{ - opacity: 0.4; - content: "\f0dc"; - } - } - - .sorting_asc{ - &:after{ - content: "\f0de"; - top: 3px; - } - } - - .sorting_desc{ - &:after{ - content: "\f0dd"; - top: -3px; - } - } - } - - > thead > tr > th, - > tbody > tr > th, - > tfoot > tr > th, - > thead > tr > td, - > tbody > tr > td, - > tfoot > tr > td{ - padding: 8px !important; - outline: 0; - } - - > thead > tr > th{ - border: none; - } -} - -.fresh-datatables{ - .pagination { - > li > a, - > li:first-child > a, - > li:first-child > span, - > li:last-child > a, - > li:last-child > span{ - border-radius: 25px; - } - } -} - - - -.dataTables_paginate{ - a{ - outline: 0; - } -} - -table.dataTable.dtr-inline.collapsed { - > tbody > tr > td.child, - > tbody > tr > th.child, - > tbody > tr > td.dataTables_empty{ - cursor: default !important; - } - - > tbody > tr > td.child, - > tbody > tr > th.child, - > tbody > tr > td.dataTables_empty{ - &:before{ - display: none !important; - } - } - - > tbody > tr > td:first-child, - > tbody > tr > th:first-child{ - position: relative; - padding-left: 30px; - cursor: pointer; - } - - > tbody > tr > td:first-child, - > tbody > tr > th:first-child{ - &:before{ - top: 50%; - margin-top: -9px; - left: 4px; - height: 18px; - width: 18px; - display: block; - position: absolute; - color: #518607; - border: 0px solid white; - border-radius: 14px; - box-shadow: 0 0 3px #444; - box-sizing: content-box; - text-align: center; - font-family: 'Courier New', Courier, monospace; - line-height: 18px; - content: '+'; - background-color: #FFF; - } - } - - > tbody > tr.parent > td:first-child, - > tbody > tr.parent > th:first-child{ - &:before{ - content: '-'; - color: #ED362C; - } - } - - > tbody > tr.child td{ - &:before{ - display: none; - } - } -} - - -table.dataTable.dtr-inline.collapsed.compact{ - > tbody > tr > td, - > tbody > tr > th{ - &:first-child{ - padding-left: 27px; - } - } - - > tbody > tr > td, - > tbody > tr > th{ - &:first-child:before{ - top: 5px; - left: 4px; - height: 14px; - width: 14px; - border-radius: 14px; - line-height: 14px; - text-indent: 3px; - } - } -} - -table.dataTable.dtr-column{ - > tbody > tr > td.control, - > tbody > tr > th.control{ - position: relative; - cursor: pointer; - } - - > tbody > tr > td.control, - > tbody > tr > th.control{ - &:before{ - top: 50%; - left: 50%; - height: 16px; - width: 16px; - margin-top: -10px; - margin-left: -10px; - display: block; - position: absolute; - color: white; - border: 2px solid white; - border-radius: 14px; - box-shadow: 0 0 3px #444; - box-sizing: content-box; - text-align: center; - font-family: 'Courier New', Courier, monospace; - line-height: 14px; - content: '+'; - background-color: #31b131; - } - } - - > tbody > tr.parent td.control, - > tbody > tr.parent th.control{ - &:before{ - content: '-'; - background-color: #d33333; - } - } -} - -table.dataTable{ - > tbody > tr.child { - padding: 0.5em 1em; - } - - > tbody > tr.child{ - &:hover{ - background: transparent !important; - } - } - - > tbody > tr.child ul { - display: inline-block; - list-style-type: none; - margin: 0; - padding: 0; - } - - > tbody > tr.child ul li { - border-bottom: 1px solid #efefef; - padding: 0.5em 0; - } - - > tbody > tr.child ul li{ - &:first-child{ - padding-top: 0; - } - } - - > tbody > tr.child ul li{ - &:last-child{ - border-bottom: none; - } - } - - > tbody > tr.child span.dtr-title { - display: inline-block; - min-width: 75px; - font-weight: bold; - } -} - -div.dtr-modal { - position: fixed; - box-sizing: border-box; - top: 0; - left: 0; - height: 100%; - width: 100%; - z-index: 100; - padding: 10em 1em; - - div.dtr-modal-display { - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - width: 50%; - height: 50%; - overflow: auto; - margin: auto; - z-index: 102; - overflow: auto; - background-color: #f5f5f7; - border: 1px solid black; - border-radius: 0.5em; - box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6); - } - - div.dtr-modal-content { - position: relative; - padding: 1em; - } - - div.dtr-modal-close { - position: absolute; - top: 6px; - right: 6px; - width: 22px; - height: 22px; - border: 1px solid #eaeaea; - background-color: #f9f9f9; - text-align: center; - border-radius: 3px; - cursor: pointer; - z-index: 12; - } - - div.dtr-modal-close{ - &:hover{ - background-color: #eaeaea; - } - } - - div.dtr-modal-background { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 101; - background: rgba(0, 0, 0, 0.6); - } -} - -@media screen and (max-width: 767px) { - div.dtr-modal div.dtr-modal-display { - width: 95%; - } -} diff --git a/frontend/assets/sass/nomad-ui/plugins/_datetime-picker.scss b/frontend/assets/sass/nomad-ui/plugins/_datetime-picker.scss deleted file mode 100644 index 2a9ccfde..00000000 --- a/frontend/assets/sass/nomad-ui/plugins/_datetime-picker.scss +++ /dev/null @@ -1,440 +0,0 @@ -/*! - * Datetimepicker for Bootstrap 3 - * ! version : 4.7.14 - * https://github.com/Eonasdan/bootstrap-datetimepicker/ - */ -$bs-datetimepicker-timepicker-font-size: 1.2em !default; -$bs-datetimepicker-active-bg: $info-color !default; -$bs-datetimepicker-active-color: $white-color !default; -$bs-datetimepicker-border-radius: $border-radius-base; -$bs-datetimepicker-btn-hover-bg: $light-gray !default; -$bs-datetimepicker-disabled-color: $medium-gray !default; -$bs-datetimepicker-alternate-color: $medium-gray !default; -$bs-datetimepicker-secondary-border-color: #ccc !default; -$bs-datetimepicker-secondary-border-color-rgba: rgba(0, 0, 0, 0.2) !default; -$bs-datetimepicker-primary-border-color: white !default; -$bs-datetimepicker-text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25) !default; - -.sr-only { - position: absolute; - width: 1px; - height: 1px; - margin: -1px; - padding: 0; - overflow: hidden; - clip: rect(0,0,0,0); - border: 0; -} - - -.bootstrap-datetimepicker-widget { - list-style: none; - - - &.dropdown-menu { - padding: 4px; - width: 19em; - - &.timepicker-sbs { - @media (min-width: $screen-sm-min) { - width: 38em; - } - - @media (min-width: $screen-md-min) { - width: 38em; - } - - @media (min-width: $screen-lg-min) { - width: 38em; - } - } - - &.bottom { - - &:before { - border-bottom: 11px solid rgba(0, 0, 0, 0.2); - border-left: 11px solid rgba(0, 0, 0, 0); - border-right: 11px solid rgba(0, 0, 0, 0); - content: ""; - display: inline-block; - position: absolute; - left: 12px; - top: -11px; - } - - &:after { - border-bottom: 11px solid #FFFFFF; - border-left: 11px solid rgba(0, 0, 0, 0); - border-right: 11px solid rgba(0, 0, 0, 0); - content: ""; - display: inline-block; - position: absolute; - left: 12px; - top: -10px; - } - } - - &.top { - margin-top: auto; - margin-bottom: -20px; - - &.open{ - margin-top: auto; - margin-bottom: 5px; - } - - &:before { - border-top: 11px solid rgba(0, 0, 0, 0.2); - border-left: 11px solid rgba(0, 0, 0, 0); - border-right: 11px solid rgba(0, 0, 0, 0); - border-bottom: none; - content: ""; - display: inline-block; - position: absolute; - left: 12px; - bottom: -11px; - top: auto; - } - - &:after { - border-top: 11px solid #FFFFFF; - border-left: 11px solid rgba(0, 0, 0, 0); - border-right: 11px solid rgba(0, 0, 0, 0); - border-bottom: none; - content: ""; - display: inline-block; - position: absolute; - left: 12px; - bottom: -10px; - top: auto; - } - } - - - - &.pull-right { - &:before { - left: auto; - right: 6px; - } - - &:after { - left: auto; - right: 7px; - } - } - } - - .list-unstyled { - margin: 0; - } - - a[data-action] { - padding: 6px 0; - border-width: 0; - } - - a[data-action]:active { - box-shadow: none; - } - - .timepicker-hour, .timepicker-minute, .timepicker-second { - width: 56px; - height: 56px; - font-weight: $font-weight-light; - font-size: $font-size-h4; - margin: 3px; - border-radius: 50%; - } - - button[data-action] { - padding: 6px; - } - - .btn[data-action="incrementHours"]::after { - @extend .sr-only; - content: "Increment Hours"; - } - - .btn[data-action="incrementMinutes"]::after { - @extend .sr-only; - content: "Increment Minutes"; - } - - .btn[data-action="decrementHours"]::after { - @extend .sr-only; - content: "Decrement Hours"; - } - - .btn[data-action="decrementMinutes"]::after { - @extend .sr-only; - content: "Decrement Minutes"; - } - - .btn[data-action="showHours"]::after { - @extend .sr-only; - content: "Show Hours"; - } - - .btn[data-action="showMinutes"]::after { - @extend .sr-only; - content: "Show Minutes"; - } - - .btn[data-action="togglePeriod"]::after { - @extend .sr-only; - content: "Toggle AM/PM"; - } - - .btn[data-action="clear"]::after { - @extend .sr-only; - content: "Clear the picker"; - } - - .btn[data-action="today"]::after { - @extend .sr-only; - content: "Set the date to today"; - } - - .picker-switch { - text-align: center; - border-radius: $bs-datetimepicker-border-radius; - - &::after { - @extend .sr-only; - content: "Toggle Date and Time Screens"; - } - - td { - padding: 0; - margin: 0; - height: auto; - width: auto; - line-height: inherit; - - span { - line-height: 2.5; - height: 2.5em; - width: 100%; - border-radius: $bs-datetimepicker-border-radius; - margin: 2px 0px !important; - } - } - } - - table { - width: 100%; - margin: 0; - - - & td > div, - & th > div { - @extend .animation-transition-fast; - text-align: center; - - } - - - & th { - @extend .animation-transition-fast; - - height: 20px; - line-height: 20px; - width: 20px; - - &.picker-switch { - width: 145px; - } - - &.disabled, - &.disabled:hover { - background: none; - color: $bs-datetimepicker-disabled-color; - cursor: not-allowed; - } - - &.prev span, - &.next span{ - border-radius: $bs-datetimepicker-border-radius; - height: 27px; - width: 27px; - line-height: 28px; - font-size: 12px; - border-radius: 50%; - text-align: center; - - } - - &.prev::after { - @extend .sr-only; - content: "Previous Month"; - } - - &.next::after { - @extend .sr-only; - content: "Next Month"; - } - - &.dow{ - text-align: center; - border-bottom: 1px solid $light-gray; - font-size: $font-size-small; - text-transform: uppercase; - color: $dark-gray; - font-weight: $font-weight-normal; - padding-bottom: 5px; - padding-top: $padding-default-vertical; - } - } - - & thead tr:first-child th{ - cursor: pointer; - - &:hover span, - &.picker-switch:hover{ - background: $bs-datetimepicker-btn-hover-bg; - } - } - - & td{ - > div { - border-radius: $bs-datetimepicker-border-radius; - - height: 54px; - line-height: 54px; - width: 54px; - text-align: center; - } - - &.cw > div { - font-size: .8em; - height: 20px; - line-height: 20px; - color: $bs-datetimepicker-alternate-color; - } - - &.day > div { - height: 30px; - line-height: 30px; - width: 30px; - text-align: center; - padding: 0px; - border-radius: 50%; - } - - &.minute > div, - &.hour > div{ - border-radius: 50%; - } - - &.day:hover > div, - &.hour:hover > div, - &.minute:hover > div, - &.second:hover > div { - background: $bs-datetimepicker-btn-hover-bg; - cursor: pointer; - } - - &.old > div, - &.new > div{ - color: $bs-datetimepicker-alternate-color; - } - - &.today > div{ - position: relative; - - &:before { - content: ''; - display: inline-block; - border: 0 0 7px 7px solid transparent; - border-bottom-color: $bs-datetimepicker-active-bg; - border-top-color: $bs-datetimepicker-secondary-border-color-rgba; - position: absolute; - bottom: 4px; - right: 4px; - } - } - - &.active > div, - &.active:hover > div { - background-color: $bs-datetimepicker-active-bg; - color: $bs-datetimepicker-active-color; - - } - - &.active.today:before > div{ - border-bottom-color: #fff; - } - - &.disabled > div, - &.disabled:hover > div { - background: none; - color: $bs-datetimepicker-disabled-color; - cursor: not-allowed; - } - - span { - @extend .animation-transition-fast; - - display: inline-block; - width: 56px; - height: 56px; - line-height: 56px; - margin: 3px 3px; - cursor: pointer; - border-radius: 50%; - text-align: center; - - &:hover { - background: $bs-datetimepicker-btn-hover-bg; - } - - &.active { - background-color: $bs-datetimepicker-active-bg; - color: $bs-datetimepicker-active-color; - } - - &.old { - color: $bs-datetimepicker-alternate-color; - } - - &.disabled, - &.disabled:hover { - background: none; - color: $bs-datetimepicker-disabled-color; - cursor: not-allowed; - } - } - } - } - - .timepicker-picker, - .timepicker-hours, - .timepicker-minutes{ - span{ - border-radius: 50% !important; - } - } - - &.usetwentyfour { - td.hour { - height: 27px; - line-height: 27px; - } - } -} - -.input-group.date { - & .input-group-addon { - cursor: pointer; - } -} - -.table-condensed>tbody>tr>td, -.table-condensed>tbody>tr>th, -.table-condensed>tfoot>tr>td, -.table-condensed>tfoot>tr>th, -.table-condensed>thead>tr>td, -.table-condensed>thead>tr>th{ - padding: 1px; -} diff --git a/frontend/assets/sass/nomad-ui/plugins/_fullcalendar.scss b/frontend/assets/sass/nomad-ui/plugins/_fullcalendar.scss deleted file mode 100644 index d359c684..00000000 --- a/frontend/assets/sass/nomad-ui/plugins/_fullcalendar.scss +++ /dev/null @@ -1,1114 +0,0 @@ -/*! - * FullCalendar v2.4.0 Stylesheet - * Docs & License: http://fullcalendar.io/ - * (c) 2015 Adam Shaw - */ - - -.fc { - direction: ltr; - text-align: left; -} - -.fc-rtl { - text-align: right; -} - -body .fc { /* extra precedence to overcome jqui */ - font-size: 1em; -} - - -/* Colors ---------------------------------------------------------------------------------------------------*/ - -.fc-unthemed th, -.fc-unthemed td, -.fc-unthemed thead, -.fc-unthemed tbody, -.fc-unthemed .fc-divider, -.fc-unthemed .fc-row, -.fc-unthemed .fc-popover { - border-color: #ddd; -} - -.fc-unthemed .fc-popover { - background-color: #fff; -} - -.fc-unthemed .fc-divider, -.fc-unthemed .fc-popover .fc-header { - background: #eee; -} - -.fc-unthemed .fc-popover .fc-header .fc-close { - color: #666; -} - -.fc-unthemed .fc-today { - background: $smoke-bg; -} - -.fc-highlight { /* when user is selecting cells */ - background: #bce8f1; - opacity: .3; - filter: alpha(opacity=30); /* for IE */ -} - -.fc-bgevent { /* default look for background events */ - background: rgb(143, 223, 130); - opacity: .3; - filter: alpha(opacity=30); /* for IE */ -} - -.fc-nonbusiness { /* default look for non-business-hours areas */ - /* will inherit .fc-bgevent's styles */ - background: #d7d7d7; -} - - -/* Icons (inline elements with styled text that mock arrow icons) ---------------------------------------------------------------------------------------------------*/ - -.fc-icon { - display: inline-block; - width: 1em; - height: 1em; - line-height: 1em; - font-size: 1em; - text-align: center; - overflow: hidden; - font-family: "Courier New", Courier, monospace; - - /* don't allow browser text-selection */ - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - } - -/* -Acceptable font-family overrides for individual icons: - "Arial", sans-serif - "Times New Roman", serif - -NOTE: use percentage font sizes or else old IE chokes -*/ - -.fc-icon:after { - position: relative; - margin: 0 -1em; /* ensures character will be centered, regardless of width */ -} - -.fc-icon-left-single-arrow:after { - content: "\02039"; - font-weight: bold; - font-size: 200%; - top: -7%; - left: 3%; -} - -.fc-icon-right-single-arrow:after { - content: "\0203A"; - font-weight: bold; - font-size: 200%; - top: -7%; - left: -3%; -} - -.fc-icon-left-double-arrow:after { - content: "\000AB"; - font-size: 160%; - top: -7%; -} - -.fc-icon-right-double-arrow:after { - content: "\000BB"; - font-size: 160%; - top: -7%; -} - -.fc-icon-left-triangle:after { - content: "\25C4"; - font-size: 125%; - top: 3%; - left: -2%; -} - -.fc-icon-right-triangle:after { - content: "\25BA"; - font-size: 125%; - top: 3%; - left: 2%; -} - -.fc-icon-down-triangle:after { - content: "\25BC"; - font-size: 125%; - top: 2%; -} - -.fc-icon-x:after { - content: "\000D7"; - font-size: 200%; - top: 6%; -} - - -/* Buttons (styled -

    - -
    - +
    + + + + + + + + + +
    ); } } -// Topbar.propTypes = { -// location: PropTypes.object.isRequired, -// }; +const TopbarWithRouter = withRouter(Topbar); -export default Topbar; +export default TopbarWithRouter; diff --git a/frontend/src/components/app.js b/frontend/src/components/app.js index abf86704..e8570b3b 100644 --- a/frontend/src/components/app.js +++ b/frontend/src/components/app.js @@ -1,28 +1,42 @@ import React, { PureComponent, PropTypes } from 'react'; -import Sidebar from './Sidebar/Sidebar'; +import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; +import injectTapEventPlugin from 'react-tap-event-plugin'; +import { green500, green800, green900 } from 'material-ui/styles/colors'; +import getMuiTheme from 'material-ui/styles/getMuiTheme'; import Topbar from './Topbar/Topbar'; +const muiTheme = getMuiTheme({ + palette: { + primary1Color: green500, + primary2Color: green800, + primary3Color: green900 + }, + appBar: { + height: 50, + }, +}); + class App extends PureComponent { + constructor(props) { + super(props); + + injectTapEventPlugin(); + } + render() { return ( -
    - -
    - -
    -
    - { this.props.children } -
    -
    + +
    + + { this.props.children }
    -
    + ); } } App.propTypes = { - location: PropTypes.object.isRequired, children: PropTypes.object.isRequired, }; diff --git a/frontend/src/containers/allocations.js b/frontend/src/containers/allocations.js index 5d772748..96a589bd 100644 --- a/frontend/src/containers/allocations.js +++ b/frontend/src/containers/allocations.js @@ -5,23 +5,7 @@ import AllocationList from '../components/AllocationList/AllocationList'; class Allocations extends Component { render() { - return ( -
    -
    -
    -
    -

    Allocations

    -
    - -
    -
    -
    - ); + return ; } } diff --git a/frontend/src/main.js b/frontend/src/main.js index c494c1d7..f5bde2c9 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -2,15 +2,14 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { browserHistory } from 'react-router'; import { Provider } from 'react-redux'; + // import Perf from 'react-addons-perf'; -import 'bootstrap/dist/css/bootstrap.min.css'; +// import 'bootstrap/dist/css/bootstrap.min.css'; +import '../assets/nomad-ui.css'; import AppRouter from './router'; import configureStore from './store'; -import '../assets/css/pe-icon-7-stroke.css'; -import '../assets/sass/nomad-ui.scss'; - // Perf.start(); configureStore().then((store) => { diff --git a/frontend/webpack-base.config.js b/frontend/webpack-base.config.js index e407f584..614f3816 100644 --- a/frontend/webpack-base.config.js +++ b/frontend/webpack-base.config.js @@ -17,30 +17,7 @@ module.exports = { } ], loaders: [ - { - test: /\.png$/, - loader: "url?limit=100000&name=static/[hash].[ext]&path=/static/" - }, - { - test: /\.jpg$/, - loader: "file?name=static/[hash].[ext]&path=/static/" - }, - { - test: /\.(woff|woff2)/, - loader: 'url?limit=10000&mimetype=application/font-woff&name=static/[hash].[ext]&path=/static/' - }, - { - test: /\.ttf/, - loader: 'url?limit=10000&mimetype=application/octet-stream&name=static/[hash].[ext]&path=/static/' - }, - { - test: /\.eot/, - loader: 'file?name=static/[hash].[ext]&path=/static/' - }, - { - test: /\.svg/, - loader: 'url?limit=10000&mimetype=image/svg+xml&name=static/[hash].[ext]&path=/static/' - } + ] }, eslint: { diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js index e9b705ab..0a253a32 100644 --- a/frontend/webpack.config.js +++ b/frontend/webpack.config.js @@ -7,13 +7,16 @@ webpackConfig = merge(webpackConfig, { output: { filename: 'static/bundle.js' }, + entry: [ 'webpack-dev-server/client?http://localhost:3333', 'webpack/hot/only-dev-server', 'babel-polyfill', './src/main.js' ], + devtool: 'cheap-module-eval-source-map', + plugins: [ new HtmlWebpackPlugin({ title: 'Nomad UI', @@ -26,12 +29,14 @@ webpackConfig = merge(webpackConfig, { new webpack.DefinePlugin({ 'process.env.GO_PORT': process.env.GO_PORT || 3000 }), new webpack.HotModuleReplacementPlugin() ], + devServer: { port: 3333, hot: true, historyApiFallback: true, publicPath: webpackConfig.output.publicPath }, + module: { loaders: [ { @@ -45,13 +50,10 @@ webpackConfig = merge(webpackConfig, { 'react-hot', 'babel?presets[]=es2015&presets[]=es2016&presets[]=react&presets[]=react-optimize&plugins[]=transform-react-inline-elements&plugins[]=syntax-trailing-function-commas&plugins[]=transform-runtime&plugins[]=transform-class-properties&plugins[]=transform-object-rest-spread' ] - }, - { - test: /\.scss$/, - loader: 'style!css?-autprefixer!postcss!sass' } ] }, + externals: { 'react/addons': true, 'react/lib/ExecutionEnvironment': true, From 44ee78e1a5540c7358763bdf8f76570b85f7ac7a Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Mon, 5 Dec 2016 12:07:41 +0100 Subject: [PATCH 17/45] further refactor the allocation list --- frontend/index.html.ejs | 2 + .../AllocationList/AllocationList.js | 27 +++----- .../AllocationListRow/AllocationListRow.js | 59 ++++++++--------- .../AllocationStatusIcon.js | 65 +++++++++++++++++++ frontend/src/components/Topbar/Topbar.js | 2 +- 5 files changed, 104 insertions(+), 51 deletions(-) create mode 100644 frontend/src/components/AllocationStatusIcon/AllocationStatusIcon.js diff --git a/frontend/index.html.ejs b/frontend/index.html.ejs index 4689fdc1..09af07c6 100644 --- a/frontend/index.html.ejs +++ b/frontend/index.html.ejs @@ -8,6 +8,8 @@ <% } %> + + <% for (var css in htmlWebpackPlugin.files.css) { %> <% } %> diff --git a/frontend/src/components/AllocationList/AllocationList.js b/frontend/src/components/AllocationList/AllocationList.js index 6a6038b6..59d89020 100644 --- a/frontend/src/components/AllocationList/AllocationList.js +++ b/frontend/src/components/AllocationList/AllocationList.js @@ -1,10 +1,9 @@ import React, { Component, PropTypes } from 'react'; -import { DropdownButton } from 'react-bootstrap'; import { Link } from 'react-router'; import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow } from 'material-ui/Table'; import SelectField from 'material-ui/SelectField'; -import AllocationListRow from '../AllocationListRow/AllocationListRow'; import MenuItem from 'material-ui/MenuItem'; +import AllocationListRow from '../AllocationListRow/AllocationListRow'; const jobHeaderColumn = display => (display ? Job : null); @@ -16,12 +15,6 @@ let nodeIdToNameCache = {}; class AllocationList extends Component { - componentWillReceiveProps(nextProps) { - if (nextProps.nodes !== this.props.nodes) { - nodeIdToNameCache = {}; - } - } - findNodeNameById(nodeId) { if (nodeId in nodeIdToNameCache) { return nodeIdToNameCache[nodeId]; @@ -106,7 +99,9 @@ class AllocationList extends Component { }); jobs.unshift( - - Any - + + - Any - + ); return ( @@ -169,14 +164,14 @@ class AllocationList extends Component { - - ID + + ID { jobHeaderColumn(showJobColumn) } Task Group - Status + Status { clientHeaderColumn(showClientColumn) } - Age - Actions + Age + Actions @@ -196,8 +191,6 @@ AllocationList.defaultProps = { showJobColumn: true, showClientColumn: true, - - containerClassName: '', }; AllocationList.propTypes = { @@ -207,8 +200,6 @@ AllocationList.propTypes = { showJobColumn: PropTypes.bool.isRequired, showClientColumn: PropTypes.bool.isRequired, - - containerClassName: PropTypes.string.isRequired, }; export default AllocationList; diff --git a/frontend/src/components/AllocationListRow/AllocationListRow.js b/frontend/src/components/AllocationListRow/AllocationListRow.js index a7367b5c..3762cb5a 100644 --- a/frontend/src/components/AllocationListRow/AllocationListRow.js +++ b/frontend/src/components/AllocationListRow/AllocationListRow.js @@ -1,42 +1,29 @@ import React, { Component, PropTypes } from 'react'; -import { Glyphicon } from 'react-bootstrap'; import ReactTooltip from 'react-tooltip'; +import { Glyphicon } from 'react-bootstrap'; import { TableRow, TableRowColumn } from 'material-ui/Table'; -import NomadLink from '../NomadLink/NomadLink'; -import FormatTime from '../FormatTime/FormatTime'; -const clientStatusIcon = { - complete: , - running: , - lost: , - failed: , -}; +import AllocationStatusIcon from '../AllocationStatusIcon/AllocationStatusIcon'; +import FormatTime from '../FormatTime/FormatTime'; +import NomadLink from '../NomadLink/NomadLink'; const getAllocationNumberFromName = (allocationName) => { const match = /[\d+]/.exec(allocationName); return match[0]; }; -const renderClientStatus = (allocation) => { - let icon = null; - - if (allocation.ClientStatus in clientStatusIcon) { - icon = clientStatusIcon[allocation.ClientStatus]; - } - - return ( -
    - {allocation.ClientStatus} - {icon} -
    - ); -}; - const jobColumn = (allocation, display) => - (display ?
    : null); + (display ? : null); const clientColumn = (allocation, nodes, display) => - (display ? : null); + (display + ? + + + + : + null + ); const renderDesiredStatus = (allocation) => { if (allocation.DesiredDescription) { @@ -63,18 +50,26 @@ class AllocationListRow extends Component { return ( - { renderClientStatus(allocation) } - - { jobColumn(allocation, showJobColumn, nodes) } + + + + + + + { jobColumn(allocation, showJobColumn) } { allocation.TaskGroup } (#{ getAllocationNumberFromName(allocation.Name) }) - { renderDesiredStatus(allocation) } + + { renderDesiredStatus(allocation) } + { clientColumn(allocation, nodes, showClientColumn) } - - + + + + schedule, + default: schedule, + }, + running: { + stop: stop, + run: play_arrow, + default: play_arrow, + }, + failed: { + default: error, + }, + lost: { + default: cached, + }, + complete: { + stop: check, + default: stop, + }, +}; + +class AllocationStatusIcon extends PureComponent { + + render() { + const allocation = this.props.allocation; + const statusConfig = clientStatusColor[allocation.ClientStatus]; + let icon = null; + + if (allocation.DesiredStatus in statusConfig) { + icon = statusConfig[allocation.DesiredStatus]; + } else { + icon = statusConfig.default; + } + + return ( +
    + + { allocation.ClientStatus } -> { allocation.DesiredStatus } + + { icon } +
    + ); + } + +} + +AllocationStatusIcon.defaultProps = { + +}; + +AllocationStatusIcon.propTypes = { + allocation: PropTypes.object.isRequired, +}; + +export default AllocationStatusIcon; diff --git a/frontend/src/components/Topbar/Topbar.js b/frontend/src/components/Topbar/Topbar.js index 3f4031e2..5c983e96 100644 --- a/frontend/src/components/Topbar/Topbar.js +++ b/frontend/src/components/Topbar/Topbar.js @@ -43,7 +43,7 @@ class Topbar extends PureComponent { render() { return (
    - + From e9533cf5a787fdc12f1c109f531330de10c44d68 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Mon, 5 Dec 2016 12:14:52 +0100 Subject: [PATCH 18/45] fix lints --- .../src/components/AllocationList/AllocationList.js | 4 ++-- .../AllocationListRow/AllocationListRow.js | 12 ++++-------- frontend/src/components/app.js | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/frontend/src/components/AllocationList/AllocationList.js b/frontend/src/components/AllocationList/AllocationList.js index 59d89020..91ea8c34 100644 --- a/frontend/src/components/AllocationList/AllocationList.js +++ b/frontend/src/components/AllocationList/AllocationList.js @@ -11,7 +11,7 @@ const jobHeaderColumn = display => const clientHeaderColumn = display => (display ? Client : null); -let nodeIdToNameCache = {}; +const nodeIdToNameCache = {}; class AllocationList extends Component { @@ -168,7 +168,7 @@ class AllocationList extends Component { ID { jobHeaderColumn(showJobColumn) } Task Group - Status + Status { clientHeaderColumn(showClientColumn) } Age Actions diff --git a/frontend/src/components/AllocationListRow/AllocationListRow.js b/frontend/src/components/AllocationListRow/AllocationListRow.js index 3762cb5a..7cc030e2 100644 --- a/frontend/src/components/AllocationListRow/AllocationListRow.js +++ b/frontend/src/components/AllocationListRow/AllocationListRow.js @@ -1,6 +1,6 @@ +import FontIcon from 'material-ui/FontIcon'; import React, { Component, PropTypes } from 'react'; import ReactTooltip from 'react-tooltip'; -import { Glyphicon } from 'react-bootstrap'; import { TableRow, TableRowColumn } from 'material-ui/Table'; import AllocationStatusIcon from '../AllocationStatusIcon/AllocationStatusIcon'; @@ -62,7 +62,7 @@ class AllocationListRow extends Component { { allocation.TaskGroup } (#{ getAllocationNumberFromName(allocation.Name) }) - + { renderDesiredStatus(allocation) } { clientColumn(allocation, nodes, showClientColumn) } @@ -70,12 +70,8 @@ class AllocationListRow extends Component { - - + + format_align_left diff --git a/frontend/src/components/app.js b/frontend/src/components/app.js index e8570b3b..3e70bfbf 100644 --- a/frontend/src/components/app.js +++ b/frontend/src/components/app.js @@ -9,7 +9,7 @@ const muiTheme = getMuiTheme({ palette: { primary1Color: green500, primary2Color: green800, - primary3Color: green900 + primary3Color: green900, }, appBar: { height: 50, From 381aa0fb8f2d178689ec9a9f5595baf92fa7a915 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Mon, 5 Dec 2016 17:24:26 +0100 Subject: [PATCH 19/45] more UI tweaks --- frontend/.editorconfig | 8 ++ frontend/assets/nomad-ui.css | 32 ++++- .../AllocationFiles/AllocationFiles.js | 122 ++++++++++-------- .../AllocationInfo/AllocationInfo.js | 122 ++++++++++-------- .../AllocationList/AllocationList.js | 3 +- .../AllocationListRow/AllocationListRow.js | 2 +- frontend/src/components/JobInfo/JobInfo.js | 7 +- .../src/components/TableHelper/TableHelper.js | 6 +- frontend/src/components/Topbar/Topbar.js | 1 + .../ViewAllocationTopbar.js | 65 ++++++++++ frontend/src/containers/allocation.js | 23 ++-- 11 files changed, 255 insertions(+), 136 deletions(-) create mode 100644 frontend/src/components/ViewAllocationTopbar/ViewAllocationTopbar.js diff --git a/frontend/.editorconfig b/frontend/.editorconfig index d98076ae..083ed67f 100644 --- a/frontend/.editorconfig +++ b/frontend/.editorconfig @@ -33,6 +33,14 @@ charset = utf-8 insert_final_newline = true trim_trailing_whitespace = true +[*.css] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +insert_final_newline = true +trim_trailing_whitespace = true + [*.bat] end_of_line = crlf diff --git a/frontend/assets/nomad-ui.css b/frontend/assets/nomad-ui.css index 37e76b15..3af2046e 100644 --- a/frontend/assets/nomad-ui.css +++ b/frontend/assets/nomad-ui.css @@ -4,13 +4,14 @@ html { } body { - font-size: 15px; - line-height: 24px; - margin: 0; + font-size: 15px; + line-height: 24px; + margin: 0; + background: #f3f3f3 } body, h1, h2, h3, h4, h5, h6 { - margin: 0; + margin: 0; } a { @@ -20,3 +21,26 @@ a { a:hover { text-decoration: underline; } + +dl { + margin-top: 0; + margin-bottom: 20px; +} + +dt { + float: left; + width: 160px; + overflow: hidden; + clear: left; + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +dt:after { + content: " : "; +} + +dd { + margin-left: 180px; +} diff --git a/frontend/src/components/AllocationFiles/AllocationFiles.js b/frontend/src/components/AllocationFiles/AllocationFiles.js index 8e7dcfee..21714c43 100644 --- a/frontend/src/components/AllocationFiles/AllocationFiles.js +++ b/frontend/src/components/AllocationFiles/AllocationFiles.js @@ -2,7 +2,8 @@ import React, { Component, PropTypes } from 'react'; import ReactTooltip from 'react-tooltip'; import { connect } from 'react-redux'; import { Button } from 'react-bootstrap'; -import TableHelper from '../TableHelper/TableHelper'; +import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table'; +import { Card, CardTitle, CardText } from 'material-ui/Card'; import { FETCH_NODE, FETCH_DIR, @@ -17,15 +18,15 @@ class AllocationFiles extends Component { constructor(props) { super(props); - // if the alloc node already in props - // this only happens when you switch tab in the ui, this will never - // trigger if /allocations/:id/files are the directly url and first page - // you view + // if the alloc node already in props + // this only happens when you switch tab in the ui, this will never + // trigger if /allocations/:id/files are the directly url and first page + // you view if (this.findAllocNode(props)) { this.fetchDir(props, props.location.query.path || '/'); } - // push our initial state + // push our initial state this.state = { contents: '', fileWatching: false, @@ -112,15 +113,15 @@ class AllocationFiles extends Component { } findAllocNode(props) { - // Find the node that this alloc belongs to + // Find the node that this alloc belongs to const allocNode = props.nodes.find(node => node.ID === props.allocation.NodeID); - // No node for this alloc, so bail out + // No node for this alloc, so bail out if (allocNode === undefined) { return false; } - // Fetch the correct node information if the alloc node changed + // Fetch the correct node information if the alloc node changed if (props.node == null || allocNode.ID !== props.node.ID) { this.props.dispatch({ type: FETCH_NODE, @@ -130,7 +131,7 @@ class AllocationFiles extends Component { return false; } - // We've located the alloc node so go ahead and query the filesystem + // We've located the alloc node so go ahead and query the filesystem return true; } @@ -201,24 +202,37 @@ class AllocationFiles extends Component { collectFiles() { const files = this.props.directory.map(file => -
    this.handleClick(file) } key={ file.Name }> - - - - ); + + + this.handleClick(file) }> + { file.Name }{ file.IsDir ? '/' : '' } + + + + this.handleClick(file) }> + { file.IsDir ? ' - ' : file.Size } + + + + ); if ((this.props.location.query.path || '/') !== '/') { files.unshift( - this.handleClick({ Name: 'back', IsDir: true }) } key="back"> - - - - ); + this.handleClick({ Name: 'back', IsDir: true }) } key="back"> + .. + + + ); } return files; } + selectRow(a,b, c) { + console.log(a, b, c); + console.log(this); + } + render() { let hostname; let fileName; @@ -241,51 +255,53 @@ class AllocationFiles extends Component { - The file you are trying to view is too large.
    - Tailing has started from the last 250 lines.
    - Please download the file for the entire contents. -
    + The file you are trying to view is too large.
    + Tailing has started from the last 250 lines.
    + Please download the file for the entire contents. +
    - ); + ); const baseUrl = `${location.protocol}//${hostname}`; const downloadPath = `download${this.props.file.File}`; const downloadBtn = this.props.file.File ? '' : - ( - - - { oversizedWarning } - - ); + ( + + + { oversizedWarning } + + ); + + const title = "Path: " + (this.props.location.query.path || '/'); return ( -
    -
    -
    -
    -
    Path: { this.props.location.query.path || '/' }
    -
    - -
    -
    -
    -
    -
    -
    File: { fileName } - { downloadBtn } -
    - -
    -
    { this.content = c; } }> - { this.state.contents } -
    + + + +
    { file.Name }{ file.IsDir ? '/' : '' }{ file.IsDir ? '' : file.Size }
    ..
    + + + Name + Size + + + + { this.collectFiles() } + +
    + +
    +
    File: { fileName } { downloadBtn }
    +
    { this.content = c; } }> + { this.state.contents }
    -
    -
    + + + ); } } diff --git a/frontend/src/components/AllocationInfo/AllocationInfo.js b/frontend/src/components/AllocationInfo/AllocationInfo.js index b6f0d89b..d7433673 100644 --- a/frontend/src/components/AllocationInfo/AllocationInfo.js +++ b/frontend/src/components/AllocationInfo/AllocationInfo.js @@ -1,5 +1,6 @@ import React, { Component, PropTypes } from 'react'; -import { Panel, Accordion, Table } from 'react-bootstrap'; +import { Card, CardTitle, CardText } from 'material-ui/Card'; +import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table'; import { connect } from 'react-redux'; import NomadLink from '../NomadLink/NomadLink'; import MetaPayload from '../MetaPayload/MetaPayload'; @@ -19,35 +20,39 @@ class AllocationInfo extends Component { static taskState(allocation, name, states) { const title = (

    - Task state for {allocation.JobID}.{allocation.TaskGroup}.{name} (final state: {states.State}) -

    - ); + Task state history for {allocation.JobID}.{allocation.TaskGroup}.{name} (final state: {states.State}) + + ); + let lastEventTime = null; return ( - -
    - - - - - - - - - - - - + + + +
    WhenDurationTypeMessage / ReasonSignalCode
    + + + When + Duration + Type + Message / Reason + Signal + Code + + + { states.Events.map((element, index) => { if (!lastEventTime) { lastEventTime = element.Time; } const output = ( - - - - - - - - - ); + element.Message + || element.SetupError + || element.DriverError + || element.KillError + || element.DownloadError + || element.ValidationError + || element.VaultError + || element.RestartReason + || element.KillReason + || element.TaskSignalReason + } + + + { element.Signal || element.TaskSignal } + + + { element.ExitCode } + + + ); lastEventTime = element.Time; return output; })} - +
    + + + + + - { element.Type } + + + { element.Type } + + { - element.Message - || element.SetupError - || element.DriverError - || element.KillError - || element.DownloadError - || element.ValidationError - || element.VaultError - || element.RestartReason - || element.KillReason - || element.TaskSignalReason - } - { element.Signal || element.TaskSignal }{ element.ExitCode }
    -
    -
    + + ); } @@ -94,7 +105,7 @@ class AllocationInfo extends Component { const allocValues = {}; allocProps.map((allocProp) => { - allocValues[allocProp] = allocation[allocProp]; + allocValues[allocProp] = allocation[allocProp] ? allocation[allocProp] : '-'; return null; }); @@ -103,7 +114,7 @@ class AllocationInfo extends Component { return
    Loading ...
    ; } - allocValues.Job = ; + allocValues.Job = ; allocValues.TaskGroup = ( @@ -115,23 +126,20 @@ class AllocationInfo extends Component { const states = []; Object.keys(allocation.TaskStates || {}).forEach((key) => { + states.push(
    ); states.push(AllocationInfo.taskState(allocation, key, allocation.TaskStates[key])); }); return ( -
    -
    -
    - Allocation Properties +
    + + + -
    -
    -
    -
    - Task States - { states } -
    -
    + + + + { states }
    ); } diff --git a/frontend/src/components/AllocationList/AllocationList.js b/frontend/src/components/AllocationList/AllocationList.js index 91ea8c34..e824b000 100644 --- a/frontend/src/components/AllocationList/AllocationList.js +++ b/frontend/src/components/AllocationList/AllocationList.js @@ -161,6 +161,7 @@ class AllocationList extends Component {   { this.jobIdFilter() }
    + @@ -174,7 +175,7 @@ class AllocationList extends Component { Actions - + {this.filteredAllocations().map((allocation) => { return ; })} diff --git a/frontend/src/components/AllocationListRow/AllocationListRow.js b/frontend/src/components/AllocationListRow/AllocationListRow.js index 7cc030e2..7dcaca94 100644 --- a/frontend/src/components/AllocationListRow/AllocationListRow.js +++ b/frontend/src/components/AllocationListRow/AllocationListRow.js @@ -49,7 +49,7 @@ class AllocationListRow extends Component { const showClientColumn = this.props.showClientColumn; return ( - + diff --git a/frontend/src/components/JobInfo/JobInfo.js b/frontend/src/components/JobInfo/JobInfo.js index b7df8f8a..09cb6a3a 100644 --- a/frontend/src/components/JobInfo/JobInfo.js +++ b/frontend/src/components/JobInfo/JobInfo.js @@ -1,3 +1,4 @@ +import Paper from 'material-ui/Paper'; import React, { Component, PropTypes } from 'react'; import { connect } from 'react-redux'; import NomadLink from '../NomadLink/NomadLink'; @@ -14,7 +15,7 @@ class JobInfo extends Component { const job = this.props.job; const jobMetaBag = job.Meta || {}; - // Build the task groups table + // Build the task groups table const taskGroups = job.TaskGroups.map((taskGroup) => { taskGroup.Tasks.map((task) => { tasks.push( @@ -59,7 +60,7 @@ class JobInfo extends Component { return (
    -
    + Job Properties
    { jobProps.map((jobProp) => { @@ -75,7 +76,7 @@ class JobInfo extends Component { return result; }, this)}
    -
    +
    Meta Properties diff --git a/frontend/src/components/TableHelper/TableHelper.js b/frontend/src/components/TableHelper/TableHelper.js index 828ce3dd..370515dd 100644 --- a/frontend/src/components/TableHelper/TableHelper.js +++ b/frontend/src/components/TableHelper/TableHelper.js @@ -2,13 +2,13 @@ import React, { PropTypes } from 'react'; import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow } from 'material-ui/Table'; const TableHelper = ({ classes, headers, body }) => -
    - +
    + { headers.map(header => { header }) } - + { body }
    ; diff --git a/frontend/src/components/Topbar/Topbar.js b/frontend/src/components/Topbar/Topbar.js index 5c983e96..be865515 100644 --- a/frontend/src/components/Topbar/Topbar.js +++ b/frontend/src/components/Topbar/Topbar.js @@ -1,3 +1,4 @@ +import FontIcon from 'material-ui/FontIcon'; import React, { PureComponent } from 'react'; import AppBar from 'material-ui/AppBar'; import { Link, withRouter } from 'react-router'; diff --git a/frontend/src/components/ViewAllocationTopbar/ViewAllocationTopbar.js b/frontend/src/components/ViewAllocationTopbar/ViewAllocationTopbar.js new file mode 100644 index 00000000..478c1792 --- /dev/null +++ b/frontend/src/components/ViewAllocationTopbar/ViewAllocationTopbar.js @@ -0,0 +1,65 @@ +import FontIcon from 'material-ui/FontIcon'; +import React, { PureComponent } from 'react'; +import Slider from 'material-ui/Slider'; +import { BottomNavigation, BottomNavigationItem } from 'material-ui/BottomNavigation'; +import { Link, withRouter } from 'react-router'; + +const infoIcon = info_outline; +const filesIcon = storage; +const logsIcon = subject; +const rawIcon = highlight; + +class _ViewAllocationTopbar extends PureComponent { + + handleActive = (tab) => { + let path = location.pathname.split('/'); + path.pop(); + path = path.join('/') + this.props.router.push(path + '/' + tab); + } + + getActiveTab = () => { + const location = this.props.location; + const end = location.pathname.split('/').pop(); + + if (end.startsWith('info')) { + return 0; + } + + if (location.query.path && location.query.path.indexOf('alloc/logs') !== -1) { + return 2; + } + + if (end.startsWith('files')) { + return 1; + } + + if (end.startsWith('raw')) { + return 3; + } + + return 0; + } + + getStyle() { + return { + borderBottom: '1px solid #e0e0e0', + marginBottom: 10, + } + } + + render() { + return ( + + this.handleActive('info') } /> + this.handleActive('files') } /> + this.handleActive('logs') } /> + this.handleActive('raw') } /> + + ); + } +} + +const ViewAllocationTopbar = withRouter(_ViewAllocationTopbar); + +export default ViewAllocationTopbar; diff --git a/frontend/src/containers/allocation.js b/frontend/src/containers/allocation.js index 36a4bf05..a13a5eca 100644 --- a/frontend/src/containers/allocation.js +++ b/frontend/src/containers/allocation.js @@ -1,6 +1,6 @@ import React, { Component, PropTypes } from 'react'; import { connect } from 'react-redux'; -import Tabs from '../components/Tabs/Tabs'; +import ViewAllocationTopbar from '../components/ViewAllocationTopbar/ViewAllocationTopbar'; import { WATCH_ALLOC, UNWATCH_ALLOC } from '../sagas/event'; class Allocation extends Component { @@ -52,19 +52,14 @@ class Allocation extends Component { const basePath = path.substring(0, path.lastIndexOf('/')); return ( -
    -
    -
    -
    -

    Allocation: { this.props.allocation.Name }

    -
    -
    - - { this.props.children } - -
    -
    -
    +
    + + +

    Allocation: { this.props.allocation.Name }

    + +
    + + { this.props.children }
    ); } From ca18e13a63de54c81fc39a05f7fa7e3cefff4a65 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Tue, 6 Dec 2016 12:05:09 +0100 Subject: [PATCH 20/45] move to yarn and cleanup js lints --- frontend/.eslintrc.js | 48 +- frontend/Makefile | 8 +- frontend/assets/nomad-ui.css | 10 + frontend/package.json | 64 +- .../AllocationFiles/AllocationFiles.js | 317 +- .../AllocationInfo/AllocationInfo.js | 88 +- .../AllocationList/AllocationList.js | 128 +- .../AllocationListRow/AllocationListRow.js | 62 +- .../components/AllocationRaw/AllocationRaw.js | 20 +- .../AllocationStatusIcon.js | 52 +- .../ClientAllocations/ClientAllocations.js | 32 +- .../ClientEvaluations/ClientEvaluations.js | 32 +- .../src/components/ClientInfo/ClientInfo.js | 68 +- .../src/components/ClientRaw/ClientRaw.js | 22 +- .../components/ConstraintRow/ConstraintRow.js | 20 +- .../ConstraintTable/ConstraintTable.js | 32 +- .../EvaluationAllocations.js | 24 +- .../EvaluationInfo/EvaluationInfo.js | 28 +- .../EvaluationList/EvaluationList.js | 38 +- .../components/EvaluationRaw/EvaluationRaw.js | 20 +- .../components/FormatBoolean/FormatBoolean.js | 32 +- .../src/components/FormatTime/FormatTime.js | 44 +- .../JobAllocations/JobAllocations.js | 32 +- .../JobEvaluations/JobEvaluations.js | 32 +- frontend/src/components/JobInfo/JobInfo.js | 95 +- frontend/src/components/JobRaw/JobRaw.js | 20 +- .../components/JobTaskGroups/JobTaskGroups.js | 52 +- frontend/src/components/JobTasks/JobTasks.js | 60 +- .../src/components/MetaPayload/MetaPayload.js | 52 +- .../src/components/NodeStatus/NodeStatus.js | 24 +- .../src/components/NomadLink/NomadLink.js | 116 +- .../src/components/Progressbar/Progressbar.js | 40 +- frontend/src/components/RawJson/RawJson.js | 34 +- .../src/components/ServerInfo/ServerInfo.js | 42 +- .../src/components/ServerRaw/ServerRaw.js | 20 +- .../src/components/TableHelper/TableHelper.js | 12 +- frontend/src/components/Tabs/Tabs.js | 20 +- frontend/src/components/Topbar/Topbar.js | 57 +- .../ViewAllocationTopbar.js | 66 +- frontend/src/components/app.js | 38 +- frontend/src/containers/allocation.js | 70 +- frontend/src/containers/allocations.js | 22 +- frontend/src/containers/client.js | 72 +- frontend/src/containers/clients.js | 38 +- frontend/src/containers/cluster.js | 68 +- frontend/src/containers/evaluation.js | 70 +- frontend/src/containers/evaluations.js | 34 +- frontend/src/containers/events.js | 50 +- frontend/src/containers/job.js | 76 +- frontend/src/containers/jobs.js | 146 +- frontend/src/containers/server.js | 68 +- frontend/src/containers/servers.js | 40 +- frontend/src/containers/statistics.js | 50 +- frontend/src/helpers/time.js | 18 +- frontend/src/helpers/uuid.js | 6 +- frontend/src/main.js | 20 +- frontend/src/reducers/allocation.js | 20 +- frontend/src/reducers/evaluation.js | 14 +- frontend/src/reducers/filesystem.js | 18 +- frontend/src/reducers/job.js | 26 +- frontend/src/reducers/member.js | 14 +- frontend/src/reducers/node.js | 14 +- frontend/src/reducers/root.js | 20 +- frontend/src/router.js | 148 +- frontend/src/sagas/event.js | 162 +- frontend/src/store.js | 34 +- frontend/webpack-base.config.js | 6 +- frontend/webpack.config.js | 3 +- frontend/yarn.lock | 4875 +++++++++++++++++ 69 files changed, 6562 insertions(+), 1641 deletions(-) create mode 100644 frontend/yarn.lock diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js index a3adc773..5a34757b 100644 --- a/frontend/.eslintrc.js +++ b/frontend/.eslintrc.js @@ -1,23 +1,29 @@ module.exports = { - "env": { - "browser": true, - "node": true - }, - "extends": "airbnb", - "rules": { - 'indent': ['error', 2], - 'no-constant-condition': ['error', { checkLoops: false }], - 'no-console': 0, - 'no-plusplus': 0, - 'class-methods-use-this': 0, - 'arrow-body-style': 0, - 'max-len': ['error', 120], - 'react/jsx-indent': ['error', 2], - 'react/prefer-stateless-function': 0, - 'react/jsx-filename-extension': ['error', { extensions: ['.jsx', '.js'] }], - 'react/jsx-curly-spacing': [2, 'always', { 'spacing': { 'objectLiterals': 'never' }}], - 'react/self-closing-comp': ['error', { 'component': true, 'html': false }], - 'react/forbid-prop-types': 0, - 'jsx-a11y/no-static-element-interactions': 0, - } + "env": { + "es6": true, + "browser": true, + "node": true + }, + "parserOptions": { + "sourceType": "module", + }, + "extends": ["standard", "standard-react"], + "rules": { + 'indent': ['error', 2], + 'no-constant-condition': ['error', { checkLoops: false }], + 'no-console': 0, + 'no-plusplus': 0, + 'operator-linebreak': 0, + 'class-methods-use-this': 0, + 'arrow-body-style': 0, + 'max-len': ['error', 120], + 'react/jsx-indent': ['error', 2], + 'react/prefer-stateless-function': 0, + 'react/jsx-filename-extension': ['error', { extensions: ['.jsx', '.js'] }], + 'react/jsx-curly-spacing': [2, 'always', { 'spacing': { 'objectLiterals': 'never' }}], + 'react/self-closing-comp': ['error', { 'component': true, 'html': false }], + 'react/forbid-prop-types': 0, + 'jsx-a11y/no-static-element-interactions': 0, + 'jsx-a11y/anchor-has-content': 0, + } } diff --git a/frontend/Makefile b/frontend/Makefile index e89cbfbb..9b77798c 100644 --- a/frontend/Makefile +++ b/frontend/Makefile @@ -1,14 +1,14 @@ .PHONY: build build: @echo "=> building frontend ..." - npm install - npm run-script build + yarn install + yarn run build .PHONY: lint lint: @echo "=> running linter ..." - @test -e node_modules || npm install - npm run-script lint + @test -e node_modules || yarn install + yarn run lint .PHONY: clean clean: diff --git a/frontend/assets/nomad-ui.css b/frontend/assets/nomad-ui.css index 3af2046e..4f50523f 100644 --- a/frontend/assets/nomad-ui.css +++ b/frontend/assets/nomad-ui.css @@ -7,6 +7,7 @@ body { font-size: 15px; line-height: 24px; margin: 0; + padding: 0; background: #f3f3f3 } @@ -16,6 +17,7 @@ body, h1, h2, h3, h4, h5, h6 { a { text-decoration: none; + color: #449b82; } a:hover { @@ -44,3 +46,11 @@ dt:after { dd { margin-left: 180px; } + +.content-file { + height: 650px; + overflow: auto; + clear: both; + white-space: pre; + background: #f5f5f5; +} diff --git a/frontend/package.json b/frontend/package.json index 0a63aba7..171c1e43 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -23,9 +23,15 @@ "license": "MIT ", "dependencies": { "babel-polyfill": "^6.16.0", - "babel-runtime": "^6.9.2", + "babel-runtime": "^6.18.0", "bootstrap": "^3.3.6", "chart.js": "^2.1.6", + "classnames": "^2.2.5", + "eslint-config-standard": "^6.2.1", + "eslint-config-standard-react": "^4.2.0", + "eslint-plugin-promise": "^3.4.0", + "eslint-plugin-standard": "^2.0.1", + "flexboxgrid": "^6.3.1", "json-formatter-js": "^1.1.0", "material-ui": "^0.16.4", "moment": "^2.15.1", @@ -35,48 +41,48 @@ "react-addons-perf": "^15.4.1", "react-bootstrap": "^0.30.7", "react-dom": "^15.4.1", + "react-flexbox-grid": "^0.10.2", "react-redux": "^4.4.6", - "react-router": "^2.8.1", + "react-router": "^3.0.0", "react-tap-event-plugin": "^2.0.1", "react-tooltip": "^3.1.8", "redux": "^3.6.0", "redux-saga": "^0.13.0", - "superagent": "^2.1.0" + "superagent": "^3.1.0" }, "devDependencies": { "autoprefixer": "^6.3.7", - "babel-core": "^6.10.4", - "babel-eslint": "^6.1.2", - "babel-loader": "^6.2.4", - "babel-plugin-syntax-trailing-function-commas": "^6.8.0", - "babel-plugin-transform-class-properties": "^6.10.2", - "babel-plugin-transform-object-rest-spread": "^6.8.0", + "babel-core": "^6.18.2", + "babel-eslint": "^7.1.1", + "babel-loader": "^6.2.8", + "babel-plugin-syntax-trailing-function-commas": "^6.13.0", + "babel-plugin-transform-class-properties": "^6.18.0", + "babel-plugin-transform-object-rest-spread": "^6.19.0", "babel-plugin-transform-react-constant-elements": "^6.9.1", - "babel-plugin-transform-runtime": "^6.9.0", - "babel-preset-es2015": "^6.9.0", - "babel-preset-es2016": "^6.11.3", - "babel-preset-react": "^6.11.1", + "babel-plugin-transform-runtime": "^6.15.0", + "babel-preset-es2015": "^6.18.0", + "babel-preset-es2016": "^6.16.0", + "babel-preset-react": "^6.16.0", "babel-preset-react-optimize": "^1.0.1", - "css-loader": "^0.23.1", - "eslint": "^3.7.0", - "eslint-config-airbnb": "^12.0.0", - "eslint-loader": "^1.4.1", - "eslint-plugin-import": "^1.16.0", - "eslint-plugin-jsx-a11y": "^2.2.2", - "eslint-plugin-react": "^6.3.0", + "css-loader": "^0.26.1", + "eslint": "^3.11.1", + "eslint-loader": "^1.6.1", + "eslint-plugin-import": "^2.2.0", + "eslint-plugin-jsx-a11y": "^3.0.1", + "eslint-plugin-react": "^6.8.0", "extract-text-webpack-plugin": "^1.0.1", "file-loader": "^0.9.0", - "html-webpack-plugin": "^2.22.0", - "html-webpack-template": "^5.0.0", - "node-sass": "^3.8.0", - "postcss-loader": "^0.9.1", - "react-addons-test-utils": "^15.3.1", - "react-hot-loader": "^1.3.0", - "sass-loader": "^4.0.0", + "html-webpack-plugin": "^2.24.1", + "html-webpack-template": "^5.4.2", + "node-sass": "^3.13.0", + "postcss-loader": "^1.2.0", + "react-addons-test-utils": "^15.4.1", + "react-hot-loader": "^1.3.1", + "sass-loader": "^4.0.2", "style-loader": "^0.13.1", "url-loader": "^0.5.7", "webpack": "^1.13.1", - "webpack-dev-server": "^1.14.1", - "webpack-merge": "^0.14.0" + "webpack-dev-server": "^1.16.2", + "webpack-merge": "^1.0.2" } } diff --git a/frontend/src/components/AllocationFiles/AllocationFiles.js b/frontend/src/components/AllocationFiles/AllocationFiles.js index 21714c43..6e430042 100644 --- a/frontend/src/components/AllocationFiles/AllocationFiles.js +++ b/frontend/src/components/AllocationFiles/AllocationFiles.js @@ -1,29 +1,32 @@ -import React, { Component, PropTypes } from 'react'; -import ReactTooltip from 'react-tooltip'; -import { connect } from 'react-redux'; -import { Button } from 'react-bootstrap'; -import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table'; -import { Card, CardTitle, CardText } from 'material-ui/Card'; +import React, { Component, PropTypes } from 'react' +import { Grid, Row, Col } from 'react-flexbox-grid' +import ReactTooltip from 'react-tooltip' +import { connect } from 'react-redux' +import { Button } from 'react-bootstrap' +import Menu from 'material-ui/Menu' +import MenuItem from 'material-ui/MenuItem' +import FontIcon from 'material-ui/FontIcon' +import Paper from 'material-ui/Paper' import { FETCH_NODE, FETCH_DIR, CLEAR_RECEIVED_FILE_DATA, CLEAR_FILE_PATH, UNWATCH_FILE, - WATCH_FILE, -} from '../../sagas/event'; + WATCH_FILE +} from '../../sagas/event' class AllocationFiles extends Component { - constructor(props) { - super(props); + constructor (props) { + super(props) // if the alloc node already in props // this only happens when you switch tab in the ui, this will never // trigger if /allocations/:id/files are the directly url and first page // you view if (this.findAllocNode(props)) { - this.fetchDir(props, props.location.query.path || '/'); + this.fetchDir(props, props.location.query.path || '/') } // push our initial state @@ -31,230 +34,246 @@ class AllocationFiles extends Component { contents: '', fileWatching: false, initialDirectoryFetched: false, - }; + width: undefined + } + } + + updateDimensions () { + const element = document.getElementById('file_browser_pane') + const positionInfo = element.getBoundingClientRect() + const width = positionInfo.width - 75 + + this.setState({ width }) } - componentWillReceiveProps(nextProps) { + componentDidMount () { + window.addEventListener('resize', this.updateDimensions) + this.updateDimensions() + } + + componentWillReceiveProps (nextProps) { if (!this.findAllocNode(nextProps)) { - return; + return } - let stateHaveChanged = false; - const nextState = this.state; + let stateHaveChanged = false + const nextState = this.state - const nextPath = nextProps.location.query.path; - const currentPath = this.props.location.query.path; + const nextPath = nextProps.location.query.path + const currentPath = this.props.location.query.path - const nextFile = nextProps.location.query.file; - const currentFile = this.props.location.query.file; + const nextFile = nextProps.location.query.file + const currentFile = this.props.location.query.file if (currentPath !== nextPath || !this.state.initialDirectoryFetched) { - this.fetchDir(nextProps, nextPath); - nextState.initialDirectoryFetched = true; - stateHaveChanged = true; + this.fetchDir(nextProps, nextPath) + nextState.initialDirectoryFetched = true + stateHaveChanged = true } if (this.state.fileWatching && currentFile && currentFile !== nextFile) { - this.unwatchFile(nextProps, currentFile); - nextState.contents = ''; - nextState.fileWatching = false; - stateHaveChanged = true; + this.unwatchFile(nextProps, currentFile) + nextState.contents = '' + nextState.fileWatching = false + stateHaveChanged = true } if (!this.state.fileWatching && nextFile) { - this.watchFile(nextProps); - nextState.fileWatching = true; - stateHaveChanged = true; + this.watchFile(nextProps) + nextState.fileWatching = true + stateHaveChanged = true } if (this.state.fileWatching && nextProps.file.Data) { - nextState.contents = this.state.contents + nextProps.file.Data; - stateHaveChanged = true; + nextState.contents = this.state.contents + nextProps.file.Data + stateHaveChanged = true this.props.dispatch({ type: CLEAR_RECEIVED_FILE_DATA, payload: { - File: nextProps.file.File, - }, - }); + File: nextProps.file.File + } + }) } if (stateHaveChanged) { - this.setState(nextState); + this.setState(nextState) } } - componentWillUpdate() { - this.shouldScroll = (this.content.scrollTop + this.content.offsetHeight) === this.content.scrollHeight; + componentWillUpdate () { + this.shouldScroll = (this.content.scrollTop + this.content.offsetHeight) === this.content.scrollHeight } - componentDidUpdate() { + componentDidUpdate () { if (this.shouldScroll) { - this.content.scrollTop = this.content.scrollHeight; + this.content.scrollTop = this.content.scrollHeight } } - componentWillUnmount() { + componentWillUnmount () { + window.removeEventListener('resize', this.updateDimensions) + this.props.dispatch({ - type: CLEAR_FILE_PATH, - }); + type: CLEAR_FILE_PATH + }) if (!this.state.fileWatching || !this.props.location.query.file) { - return; + return } - this.unwatchFile(this.props, this.props.location.query.file); + this.unwatchFile(this.props, this.props.location.query.file) this.setState({ contents: '', fileWatching: false, - initialDirectoryFetched: false, - }); + initialDirectoryFetched: false + }) } - findAllocNode(props) { + findAllocNode (props) { // Find the node that this alloc belongs to - const allocNode = props.nodes.find(node => node.ID === props.allocation.NodeID); + const allocNode = props.nodes.find(node => node.ID === props.allocation.NodeID) // No node for this alloc, so bail out if (allocNode === undefined) { - return false; + return false } // Fetch the correct node information if the alloc node changed if (props.node == null || allocNode.ID !== props.node.ID) { this.props.dispatch({ type: FETCH_NODE, - payload: allocNode.ID, - }); + payload: allocNode.ID + }) - return false; + return false } // We've located the alloc node so go ahead and query the filesystem - return true; + return true } - fetchDir(props, dir) { + fetchDir (props, dir) { this.props.dispatch({ type: FETCH_DIR, payload: { addr: props.node.HTTPAddr, path: dir || '/', - allocID: props.allocation.ID, - }, - }); + allocID: props.allocation.ID + } + }) } - watchFile(props) { + watchFile (props) { if (!this.findAllocNode(props)) { - return; + return } - const filePath = props.location.query.path + props.location.query.file; + const filePath = props.location.query.path + props.location.query.file this.props.dispatch({ type: WATCH_FILE, payload: { addr: props.node.HTTPAddr, path: filePath, - allocID: props.allocation.ID, - }, - }); + allocID: props.allocation.ID + } + }) } - unwatchFile(props, file) { + unwatchFile (props, file) { if (!this.findAllocNode(props)) { - return; + return } props.dispatch({ type: UNWATCH_FILE, - payload: file, - }); + payload: file + }) } - handleClick(file) { - let path = this.props.location.query.path || '/'; + handleClick (file) { + let path = this.props.location.query.path || '/' if (file.IsDir) { if (file.Name === 'back') { - path = path.substr(0, path.lastIndexOf('/', path.length - 2) + 1); + path = path.substr(0, path.lastIndexOf('/', path.length - 2) + 1) } else { - path = `${path}${file.Name}/`; + path = `${path}${file.Name}/` } this.props.history.push({ pathname: this.props.location.pathname, - query: { path }, - }); - return; + query: { path } + }) + return } this.props.history.push({ pathname: this.props.location.pathname, query: { path, - file: file.Name, - }, - }); + file: file.Name + } + }) } - collectFiles() { - const files = this.props.directory.map(file => - - - this.handleClick(file) }> - { file.Name }{ file.IsDir ? '/' : '' } - - - - this.handleClick(file) }> - { file.IsDir ? ' - ' : file.Size } - - - - ); + collectFiles () { + const files = this.props.directory.map((file) => { + const a = file.IsDir ? '/' : '' + const b = file.Name + ' ' + a + const c = file.IsDir ? ' - ' : file.Size + const i = file.IsDir + ? folder + : attachment + + return this.handleClick(file) } + leftIcon={ i } + primaryText={ b } + secondaryText={ c } + /> + }) if ((this.props.location.query.path || '/') !== '/') { + const x = arrow_upward + files.unshift( - this.handleClick({ Name: 'back', IsDir: true }) } key="back"> - .. - - - ); + this.handleClick({ Name: 'back', IsDir: true }) } + leftIcon={ x } + primaryText='..' + /> + ) } - return files; + return files } - selectRow(a,b, c) { - console.log(a, b, c); - console.log(this); - } - - render() { - let hostname; - let fileName; + render () { + let hostname + let fileName if (process.env.NODE_ENV === 'production') { - hostname = location.host; + hostname = location.host } else { - hostname = `${location.hostname}:${process.env.GO_PORT}` || 3000; + hostname = `${location.hostname}:${process.env.GO_PORT}` || 3000 } if (this.state.fileWatching && this.props.file.File) { - fileName = this.props.file.File; + fileName = this.props.file.File } else { - fileName = ''; + fileName = '' } const oversizedWarning = !this.props.file.Oversized ? '' : ( - + - + The file you are trying to view is too large.
    Tailing has started from the last 250 lines.
    Please download the file for the entire contents. @@ -262,52 +281,46 @@ class AllocationFiles extends Component {
    - ); + ) - const baseUrl = `${location.protocol}//${hostname}`; - const downloadPath = `download${this.props.file.File}`; + const baseUrl = `${location.protocol}//${hostname}` + const downloadPath = `download${this.props.file.File}` const downloadBtn = this.props.file.File ? '' : - (
    - - + ( + + { oversizedWarning } - -
    ); + + ) - const title = "Path: " + (this.props.location.query.path || '/'); + const title = Current path: {this.props.location.query.path || '/'} return ( - - - - - - - Name - Size - - - - { this.collectFiles() } - -
    - -
    -
    File: { fileName } { downloadBtn }
    -
    { this.content = c; } }> - { this.state.contents } -
    -
    - -
    -
    - ); + + + + +
    { title }
    + { this.collectFiles() } +
    + + + +
    File: { fileName } { downloadBtn }
    +
    { this.content = c } }> + { this.state.contents } +
    +
    + +
    +
    + ) } } -function mapStateToProps({ allocation, nodes, node, directory, file }) { - return { allocation, nodes, node, directory, file }; +function mapStateToProps ({ allocation, nodes, node, directory, file }) { + return { allocation, nodes, node, directory, file } } AllocationFiles.propTypes = { @@ -317,7 +330,7 @@ AllocationFiles.propTypes = { dispatch: PropTypes.func.isRequired, file: PropTypes.object.isRequired, directory: PropTypes.array.isRequired, - history: PropTypes.object.isRequired, -}; + history: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(AllocationFiles); +export default connect(mapStateToProps)(AllocationFiles) diff --git a/frontend/src/components/AllocationInfo/AllocationInfo.js b/frontend/src/components/AllocationInfo/AllocationInfo.js index d7433673..1a100050 100644 --- a/frontend/src/components/AllocationInfo/AllocationInfo.js +++ b/frontend/src/components/AllocationInfo/AllocationInfo.js @@ -1,10 +1,10 @@ -import React, { Component, PropTypes } from 'react'; -import { Card, CardTitle, CardText } from 'material-ui/Card'; -import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table'; -import { connect } from 'react-redux'; -import NomadLink from '../NomadLink/NomadLink'; -import MetaPayload from '../MetaPayload/MetaPayload'; -import FormatTime from '../FormatTime/FormatTime'; +import React, { Component, PropTypes } from 'react' +import { Card, CardTitle, CardText } from 'material-ui/Card' +import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table' +import { connect } from 'react-redux' +import NomadLink from '../NomadLink/NomadLink' +import MetaPayload from '../MetaPayload/MetaPayload' +import FormatTime from '../FormatTime/FormatTime' const allocProps = [ 'ID', @@ -12,19 +12,19 @@ const allocProps = [ 'ClientStatus', 'ClientDescription', 'DesiredStatus', - 'DesiredDescription', -]; + 'DesiredDescription' +] class AllocationInfo extends Component { - static taskState(allocation, name, states) { + static taskState (allocation, name, states) { const title = (

    Task state history for {allocation.JobID}.{allocation.TaskGroup}.{name} (final state: {states.State})

    - ); + ) - let lastEventTime = null; + let lastEventTime = null return ( @@ -44,7 +44,7 @@ class AllocationInfo extends Component { { states.Events.map((element, index) => { if (!lastEventTime) { - lastEventTime = element.Time; + lastEventTime = element.Time } const output = ( @@ -57,8 +57,8 @@ class AllocationInfo extends Component { time={ element.Time } now={ lastEventTime } identifier={ allocation.ID } - durationInterval="ms" - durationFormat="h [hour] m [min] s [seconds]" + durationInterval='ms' + durationFormat='h [hour] m [min] s [seconds]' /> @@ -85,55 +85,55 @@ class AllocationInfo extends Component { { element.ExitCode } - ); + ) - lastEventTime = element.Time; - return output; + lastEventTime = element.Time + return output })} - ); + ) } - render() { - const allocation = this.props.allocation; - const jobId = allocation.JobID; - const nodeId = allocation.NodeID; - const taskGroupId = allocation.TaskGroupId; + render () { + const allocation = this.props.allocation + const jobId = allocation.JobID + const nodeId = allocation.NodeID + const taskGroupId = allocation.TaskGroupId - const allocValues = {}; + const allocValues = {} allocProps.map((allocProp) => { - allocValues[allocProp] = allocation[allocProp] ? allocation[allocProp] : '-'; - return null; - }); + allocValues[allocProp] = allocation[allocProp] ? allocation[allocProp] : '-' + return null + }) // don't render anything big until we got the allocation from the API if (!jobId) { - return
    Loading ...
    ; + return
    Loading ...
    } - allocValues.Job = ; + allocValues.Job = allocValues.TaskGroup = ( {allocation.TaskGroup} - ); + ) - allocValues.Node = ; + allocValues.Node = - const states = []; + const states = [] Object.keys(allocation.TaskStates || {}).forEach((key) => { - states.push(
    ); - states.push(AllocationInfo.taskState(allocation, key, allocation.TaskStates[key])); - }); + states.push(
    ) + states.push(AllocationInfo.taskState(allocation, key, allocation.TaskStates[key])) + }) return ( -
    +
    - + @@ -141,17 +141,17 @@ class AllocationInfo extends Component { { states }
    - ); + ) } } -function mapStateToProps({ allocation, nodes }) { - return { allocation, nodes }; +function mapStateToProps ({ allocation, nodes }) { + return { allocation, nodes } } AllocationInfo.propTypes = { allocation: PropTypes.object.isRequired, - nodes: PropTypes.array.isRequired, -}; + nodes: PropTypes.array.isRequired +} -export default connect(mapStateToProps)(AllocationInfo); +export default connect(mapStateToProps)(AllocationInfo) diff --git a/frontend/src/components/AllocationList/AllocationList.js b/frontend/src/components/AllocationList/AllocationList.js index e824b000..f75ba65d 100644 --- a/frontend/src/components/AllocationList/AllocationList.js +++ b/frontend/src/components/AllocationList/AllocationList.js @@ -1,65 +1,65 @@ -import React, { Component, PropTypes } from 'react'; -import { Link } from 'react-router'; -import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow } from 'material-ui/Table'; -import SelectField from 'material-ui/SelectField'; -import MenuItem from 'material-ui/MenuItem'; -import AllocationListRow from '../AllocationListRow/AllocationListRow'; +import React, { Component, PropTypes } from 'react' +import { Link } from 'react-router' +import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow } from 'material-ui/Table' +import SelectField from 'material-ui/SelectField' +import MenuItem from 'material-ui/MenuItem' +import AllocationListRow from '../AllocationListRow/AllocationListRow' const jobHeaderColumn = display => - (display ? Job : null); + (display ? Job : null) const clientHeaderColumn = display => - (display ? Client : null); + (display ? Client : null) -const nodeIdToNameCache = {}; +const nodeIdToNameCache = {} class AllocationList extends Component { - findNodeNameById(nodeId) { + findNodeNameById (nodeId) { if (nodeId in nodeIdToNameCache) { - return nodeIdToNameCache[nodeId]; + return nodeIdToNameCache[nodeId] } const r = Object.keys(this.props.nodes) .filter(node => this.props.nodes[node].ID === nodeId - ); + ) if (r.length !== 0) { - nodeIdToNameCache[nodeId] = this.props.nodes[r].Name; + nodeIdToNameCache[nodeId] = this.props.nodes[r].Name } else { - nodeIdToNameCache[nodeId] = nodeId; + nodeIdToNameCache[nodeId] = nodeId } - return nodeIdToNameCache[nodeId]; + return nodeIdToNameCache[nodeId] } - filteredAllocations() { - const query = this.props.location.query || {}; - let allocations = this.props.allocations; + filteredAllocations () { + const query = this.props.location.query || {} + let allocations = this.props.allocations if ('status' in query) { - allocations = allocations.filter(allocation => allocation.ClientStatus === query.status); + allocations = allocations.filter(allocation => allocation.ClientStatus === query.status) } if ('client' in query) { - allocations = allocations.filter(allocation => allocation.NodeID === query.client); + allocations = allocations.filter(allocation => allocation.NodeID === query.client) } if ('job' in query) { - allocations = allocations.filter(allocation => allocation.JobID === query.job); + allocations = allocations.filter(allocation => allocation.JobID === query.job) } - return allocations; + return allocations } - clientStatusFilter() { - const location = this.props.location; - const query = this.props.location.query || {}; + clientStatusFilter () { + const location = this.props.location + const query = this.props.location.query || {} - let title = 'Client Status'; + let title = 'Client Status' if ('status' in query) { - title = {title}: { query.status }; + title = {title}: { query.status } } return ( @@ -71,90 +71,90 @@ class AllocationList extends Component { Lost Failed - ); + ) } - jobIdFilter() { - const location = this.props.location; - const query = this.props.location.query || {}; + jobIdFilter () { + const location = this.props.location + const query = this.props.location.query || {} - let title = 'Job'; + let title = 'Job' if ('job' in query) { - title = {title}: { query.job }; + title = {title}: { query.job } } const jobs = this.props.allocations .map((allocation) => { - return allocation.JobID; + return allocation.JobID }) .filter((v, i, a) => { - return a.indexOf(v) === i; + return a.indexOf(v) === i }) .map((job) => { return ( { job } - ); - }); + ) + }) jobs.unshift( - + - Any - - ); + ) return ( { jobs } - ); + ) } - clientFilter() { - const location = this.props.location; - const query = this.props.location.query || {}; + clientFilter () { + const location = this.props.location + const query = this.props.location.query || {} - let title = 'Client'; + let title = 'Client' if ('client' in query) { - title = {title}: { this.findNodeNameById(query.client) }; + title = {title}: { this.findNodeNameById(query.client) } } const clients = this.props.allocations .map((allocation) => { - return allocation.NodeID; + return allocation.NodeID }) .filter((v, i, a) => { - return a.indexOf(v) === i; + return a.indexOf(v) === i }) .map((client) => { return ( { this.findNodeNameById(client) } - ); - }); + ) + }) clients.unshift( - + - Any - - ); + ) return ( { clients } - ); + ) } - render() { - const props = this.props; - const showJobColumn = this.props.showJobColumn; - const showClientColumn = this.props.showClientColumn; + render () { + const props = this.props + const showJobColumn = this.props.showJobColumn + const showClientColumn = this.props.showClientColumn return (
    -
    +
    { this.clientFilter() }   { this.clientStatusFilter() } @@ -177,11 +177,11 @@ class AllocationList extends Component { {this.filteredAllocations().map((allocation) => { - return ; + return })} -
    ); +
    ) } } @@ -191,8 +191,8 @@ AllocationList.defaultProps = { location: {}, showJobColumn: true, - showClientColumn: true, -}; + showClientColumn: true +} AllocationList.propTypes = { allocations: PropTypes.array.isRequired, @@ -200,7 +200,7 @@ AllocationList.propTypes = { location: PropTypes.object.isRequired, showJobColumn: PropTypes.bool.isRequired, - showClientColumn: PropTypes.bool.isRequired, -}; + showClientColumn: PropTypes.bool.isRequired +} -export default AllocationList; +export default AllocationList diff --git a/frontend/src/components/AllocationListRow/AllocationListRow.js b/frontend/src/components/AllocationListRow/AllocationListRow.js index 7dcaca94..cc78f73e 100644 --- a/frontend/src/components/AllocationListRow/AllocationListRow.js +++ b/frontend/src/components/AllocationListRow/AllocationListRow.js @@ -1,52 +1,52 @@ -import FontIcon from 'material-ui/FontIcon'; -import React, { Component, PropTypes } from 'react'; -import ReactTooltip from 'react-tooltip'; -import { TableRow, TableRowColumn } from 'material-ui/Table'; +import FontIcon from 'material-ui/FontIcon' +import React, { Component, PropTypes } from 'react' +import ReactTooltip from 'react-tooltip' +import { TableRow, TableRowColumn } from 'material-ui/Table' -import AllocationStatusIcon from '../AllocationStatusIcon/AllocationStatusIcon'; -import FormatTime from '../FormatTime/FormatTime'; -import NomadLink from '../NomadLink/NomadLink'; +import AllocationStatusIcon from '../AllocationStatusIcon/AllocationStatusIcon' +import FormatTime from '../FormatTime/FormatTime' +import NomadLink from '../NomadLink/NomadLink' const getAllocationNumberFromName = (allocationName) => { - const match = /[\d+]/.exec(allocationName); - return match[0]; -}; + const match = /[\d+]/.exec(allocationName) + return match[0] +} const jobColumn = (allocation, display) => - (display ? : null); + (display ? : null) const clientColumn = (allocation, nodes, display) => (display ? - + : null - ); + ) const renderDesiredStatus = (allocation) => { if (allocation.DesiredDescription) { return (
    {allocation.DesiredDescription} - + {allocation.DesiredStatus}
    - ); + ) } - return
    {allocation.DesiredStatus}
    ; -}; + return
    {allocation.DesiredStatus}
    +} class AllocationListRow extends Component { - render() { - const allocation = this.props.allocation; - const nodes = this.props.nodes; - const showJobColumn = this.props.showJobColumn; - const showClientColumn = this.props.showClientColumn; + render () { + const allocation = this.props.allocation + const nodes = this.props.nodes + const showJobColumn = this.props.showJobColumn + const showClientColumn = this.props.showClientColumn return ( @@ -54,7 +54,7 @@ class AllocationListRow extends Component { - + { jobColumn(allocation, showJobColumn) } @@ -70,12 +70,12 @@ class AllocationListRow extends Component { - - format_align_left + + format_align_left - ); + ) } } @@ -84,15 +84,15 @@ AllocationListRow.defaultProps = { nodes: [], showJobColumn: true, - showClientColumn: true, -}; + showClientColumn: true +} AllocationListRow.propTypes = { allocation: PropTypes.object.isRequired, nodes: PropTypes.array.isRequired, showJobColumn: PropTypes.bool.isRequired, - showClientColumn: PropTypes.bool.isRequired, -}; + showClientColumn: PropTypes.bool.isRequired +} -export default AllocationListRow; +export default AllocationListRow diff --git a/frontend/src/components/AllocationRaw/AllocationRaw.js b/frontend/src/components/AllocationRaw/AllocationRaw.js index b4b42f3f..086698a5 100644 --- a/frontend/src/components/AllocationRaw/AllocationRaw.js +++ b/frontend/src/components/AllocationRaw/AllocationRaw.js @@ -1,19 +1,19 @@ -import React, { PropTypes } from 'react'; -import { connect } from 'react-redux'; +import React, { PropTypes } from 'react' +import { connect } from 'react-redux' -import RawJson from '../RawJson/RawJson'; +import RawJson from '../RawJson/RawJson' const AllocationRaw = ({ allocation }) => -
    +
    -
    ; +
    -function mapStateToProps({ allocation }) { - return { allocation }; +function mapStateToProps ({ allocation }) { + return { allocation } } AllocationRaw.propTypes = { - allocation: PropTypes.object.isRequired, -}; + allocation: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(AllocationRaw); +export default connect(mapStateToProps)(AllocationRaw) diff --git a/frontend/src/components/AllocationStatusIcon/AllocationStatusIcon.js b/frontend/src/components/AllocationStatusIcon/AllocationStatusIcon.js index 8716fa84..5ad52ecb 100644 --- a/frontend/src/components/AllocationStatusIcon/AllocationStatusIcon.js +++ b/frontend/src/components/AllocationStatusIcon/AllocationStatusIcon.js @@ -1,7 +1,7 @@ -import React, { PureComponent, PropTypes } from 'react'; -import ReactTooltip from 'react-tooltip'; -import FontIcon from 'material-ui/FontIcon'; -import { amber500, green500, red500 } from 'material-ui/styles/colors'; +import React, { PureComponent, PropTypes } from 'react' +import ReactTooltip from 'react-tooltip' +import FontIcon from 'material-ui/FontIcon' +import { amber500, green500, red500 } from 'material-ui/styles/colors' // // map of ClientStatus and nested below the DesiredStatus @@ -9,37 +9,37 @@ import { amber500, green500, red500 } from 'material-ui/styles/colors'; const clientStatusColor = { pending: { - run: schedule, - default: schedule, + run: schedule, + default: schedule }, running: { - stop: stop, - run: play_arrow, - default: play_arrow, + stop: stop, + run: play_arrow, + default: play_arrow }, failed: { - default: error, + default: error }, lost: { - default: cached, + default: cached }, complete: { - stop: check, - default: stop, - }, -}; + stop: check, + default: stop + } +} class AllocationStatusIcon extends PureComponent { - render() { - const allocation = this.props.allocation; - const statusConfig = clientStatusColor[allocation.ClientStatus]; - let icon = null; + render () { + const allocation = this.props.allocation + const statusConfig = clientStatusColor[allocation.ClientStatus] + let icon = null if (allocation.DesiredStatus in statusConfig) { - icon = statusConfig[allocation.DesiredStatus]; + icon = statusConfig[allocation.DesiredStatus] } else { - icon = statusConfig.default; + icon = statusConfig.default } return ( @@ -49,17 +49,17 @@ class AllocationStatusIcon extends PureComponent { { icon }
    - ); + ) } } AllocationStatusIcon.defaultProps = { -}; +} AllocationStatusIcon.propTypes = { - allocation: PropTypes.object.isRequired, -}; + allocation: PropTypes.object.isRequired +} -export default AllocationStatusIcon; +export default AllocationStatusIcon diff --git a/frontend/src/components/ClientAllocations/ClientAllocations.js b/frontend/src/components/ClientAllocations/ClientAllocations.js index b013dfb1..cfa198db 100644 --- a/frontend/src/components/ClientAllocations/ClientAllocations.js +++ b/frontend/src/components/ClientAllocations/ClientAllocations.js @@ -1,40 +1,40 @@ -import React, { PureComponent, PropTypes } from 'react'; -import { connect } from 'react-redux'; -import AllocationList from '../AllocationList/AllocationList'; +import React, { PureComponent, PropTypes } from 'react' +import { connect } from 'react-redux' +import AllocationList from '../AllocationList/AllocationList' class ClientAllocations extends PureComponent { - render() { - const nodeId = this.props.params.nodeId; - const allocs = this.props.allocations.filter(allocation => allocation.NodeID === nodeId); + render () { + const nodeId = this.props.params.nodeId + const allocs = this.props.allocations.filter(allocation => allocation.NodeID === nodeId) return ( -
    +
    - ); + ) } } -function mapStateToProps({ allocations }) { - return { allocations }; +function mapStateToProps ({ allocations }) { + return { allocations } } ClientAllocations.defaultProps = { allocations: [], params: {}, - location: {}, -}; + location: {} +} ClientAllocations.propTypes = { allocations: PropTypes.array.isRequired, params: PropTypes.object.isRequired, - location: PropTypes.object.isRequired, -}; + location: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(ClientAllocations); +export default connect(mapStateToProps)(ClientAllocations) diff --git a/frontend/src/components/ClientEvaluations/ClientEvaluations.js b/frontend/src/components/ClientEvaluations/ClientEvaluations.js index a7ba7ba3..2c931dd9 100644 --- a/frontend/src/components/ClientEvaluations/ClientEvaluations.js +++ b/frontend/src/components/ClientEvaluations/ClientEvaluations.js @@ -1,33 +1,33 @@ -import React, { PureComponent, PropTypes } from 'react'; -import { connect } from 'react-redux'; -import EvaluationList from '../EvaluationList/EvaluationList'; +import React, { PureComponent, PropTypes } from 'react' +import { connect } from 'react-redux' +import EvaluationList from '../EvaluationList/EvaluationList' class ClientEvaluations extends PureComponent { - render() { - const nodeId = this.props.params.nodeId; - const evals = this.props.evaluations.filter(evaluation => evaluation.NodeID === nodeId); + render () { + const nodeId = this.props.params.nodeId + const evals = this.props.evaluations.filter(evaluation => evaluation.NodeID === nodeId) return ( -
    - +
    +
    - ); + ) } } -function mapStateToProps({ evaluations }) { - return { evaluations }; +function mapStateToProps ({ evaluations }) { + return { evaluations } } ClientEvaluations.defaultProps = { evaluations: [], - params: {}, -}; + params: {} +} ClientEvaluations.propTypes = { evaluations: PropTypes.array.isRequired, - params: PropTypes.object.isRequired, -}; + params: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(ClientEvaluations); +export default connect(mapStateToProps)(ClientEvaluations) diff --git a/frontend/src/components/ClientInfo/ClientInfo.js b/frontend/src/components/ClientInfo/ClientInfo.js index 34cacf19..e3501e3d 100644 --- a/frontend/src/components/ClientInfo/ClientInfo.js +++ b/frontend/src/components/ClientInfo/ClientInfo.js @@ -1,6 +1,6 @@ -import React, { PropTypes } from 'react'; -import { connect } from 'react-redux'; -import MetaPayload from '../MetaPayload/MetaPayload'; +import React, { PropTypes } from 'react' +import { connect } from 'react-redux' +import MetaPayload from '../MetaPayload/MetaPayload' const nodeProps = [ 'ID', @@ -9,27 +9,27 @@ const nodeProps = [ 'Datacenter', 'Drain', 'HTTPAddr', - 'NodeClass', -]; + 'NodeClass' +] -const withPrefix = function withPrefix(obj, prefix) { - const result = {}; +const withPrefix = function withPrefix (obj, prefix) { + const result = {} Object.keys(obj || {}).forEach((key) => { if (key.startsWith(prefix)) { - result[key.replace(prefix, '')] = obj[key]; + result[key.replace(prefix, '')] = obj[key] } - }); + }) - return result; -}; + return result +} const ClientInfo = ({ node }) => -
    -
    -
    +
    +
    +
    Client Properties -
    +
    { nodeProps.map(nodeProp =>
    { nodeProp }
    @@ -38,41 +38,41 @@ const ClientInfo = ({ node }) => )}
    -
    +
    Meta Properties - +
    -
    -
    +
    +
    CPU Attributes - +
    -
    +
    Driver Attributes - +
    -
    +
    Kernel Attributes - +
    -
    +
    Unique Attributes - +
    -
    +
    Nomad Attributes - +
    -
    ; +
    -function mapStateToProps({ node }) { - return { node }; +function mapStateToProps ({ node }) { + return { node } } ClientInfo.propTypes = { - node: PropTypes.object.isRequired, -}; + node: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(ClientInfo); +export default connect(mapStateToProps)(ClientInfo) diff --git a/frontend/src/components/ClientRaw/ClientRaw.js b/frontend/src/components/ClientRaw/ClientRaw.js index 1c6a7629..de639dc9 100644 --- a/frontend/src/components/ClientRaw/ClientRaw.js +++ b/frontend/src/components/ClientRaw/ClientRaw.js @@ -1,21 +1,21 @@ -import React, { PropTypes } from 'react'; -import { connect } from 'react-redux'; +import React, { PropTypes } from 'react' +import { connect } from 'react-redux' -import RawJson from '../RawJson/RawJson'; +import RawJson from '../RawJson/RawJson' const ClientRaw = ({ node }) => -
    -
    +
    +
    -
    ; +
    -function mapStateToProps({ node }) { - return { node }; +function mapStateToProps ({ node }) { + return { node } } ClientRaw.propTypes = { - node: PropTypes.object.isRequired, -}; + node: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(ClientRaw); +export default connect(mapStateToProps)(ClientRaw) diff --git a/frontend/src/components/ConstraintRow/ConstraintRow.js b/frontend/src/components/ConstraintRow/ConstraintRow.js index 0c6a3f47..f5240482 100644 --- a/frontend/src/components/ConstraintRow/ConstraintRow.js +++ b/frontend/src/components/ConstraintRow/ConstraintRow.js @@ -1,13 +1,13 @@ -import React, { PropTypes } from 'react'; +import React, { PropTypes } from 'react' const ConstraintRow = ({ constraint }) => { // unique case as it does not expose any LTarget or RTarget if (constraint.Operand === 'distinct_hosts') { return ( - Distinct Hosts + Distinct Hosts - ); + ) } return ( @@ -16,15 +16,15 @@ const ConstraintRow = ({ constraint }) => { { constraint.Operand } { constraint.RTarget } - ); -}; + ) +} ConstraintRow.defaultProps = { - constraint: {}, -}; + constraint: {} +} ConstraintRow.propTypes = { - constraint: PropTypes.object.isRequired, -}; + constraint: PropTypes.object.isRequired +} -export default ConstraintRow; +export default ConstraintRow diff --git a/frontend/src/components/ConstraintTable/ConstraintTable.js b/frontend/src/components/ConstraintTable/ConstraintTable.js index 7ae5140f..728a1194 100644 --- a/frontend/src/components/ConstraintTable/ConstraintTable.js +++ b/frontend/src/components/ConstraintTable/ConstraintTable.js @@ -1,16 +1,16 @@ -import React, { Component, PropTypes } from 'react'; -import ReactTooltip from 'react-tooltip'; -import ConstraintRow from '../ConstraintRow/ConstraintRow'; +import React, { Component, PropTypes } from 'react' +import ReactTooltip from 'react-tooltip' +import ConstraintRow from '../ConstraintRow/ConstraintRow' class ConstraintTable extends Component { - render() { - function getUniqueKeyForConstraint(constraint) { - return (`${constraint.LTarget}@${constraint.RTarget}@${constraint.Operand}`); + render () { + function getUniqueKeyForConstraint (constraint) { + return (`${constraint.LTarget}@${constraint.RTarget}@${constraint.Operand}`) } if (this.props.constraints === null || this.props.constraints.length === 0) { - return -; + return - } const table = ( @@ -32,33 +32,33 @@ class ConstraintTable extends Component { )} - ); + ) if (this.props.asTooltip) { return (
    { table } - + { this.props.constraints.length } constraints
    - ); + ) } - return table; + return table } } ConstraintTable.defaultProps = { constraints: [], asTooltip: false, - idPrefix: null, -}; + idPrefix: null +} ConstraintTable.propTypes = { constraints: PropTypes.array, idPrefix: PropTypes.string, - asTooltip: PropTypes.bool.isRequired, -}; + asTooltip: PropTypes.bool.isRequired +} -export default ConstraintTable; +export default ConstraintTable diff --git a/frontend/src/components/EvaluationAllocations/EvaluationAllocations.js b/frontend/src/components/EvaluationAllocations/EvaluationAllocations.js index d040459d..fc5c9af9 100644 --- a/frontend/src/components/EvaluationAllocations/EvaluationAllocations.js +++ b/frontend/src/components/EvaluationAllocations/EvaluationAllocations.js @@ -1,23 +1,23 @@ -import React, { PropTypes } from 'react'; -import { connect } from 'react-redux'; -import AllocationList from '../AllocationList/AllocationList'; +import React, { PropTypes } from 'react' +import { connect } from 'react-redux' +import AllocationList from '../AllocationList/AllocationList' const EvaluationAllocations = ({ allocations, evaluation, nodes }) => { - const allocs = allocations.filter(allocation => allocation.EvalID === evaluation.ID); + const allocs = allocations.filter(allocation => allocation.EvalID === evaluation.ID) return ( - - ); -}; + + ) +} -function mapStateToProps({ evaluation, allocations, nodes }) { - return { evaluation, allocations, nodes }; +function mapStateToProps ({ evaluation, allocations, nodes }) { + return { evaluation, allocations, nodes } } EvaluationAllocations.propTypes = { allocations: PropTypes.array.isRequired, evaluation: PropTypes.object.isRequired, - nodes: PropTypes.array.isRequired, -}; + nodes: PropTypes.array.isRequired +} -export default connect(mapStateToProps)(EvaluationAllocations); +export default connect(mapStateToProps)(EvaluationAllocations) diff --git a/frontend/src/components/EvaluationInfo/EvaluationInfo.js b/frontend/src/components/EvaluationInfo/EvaluationInfo.js index de773b06..4edc0b82 100644 --- a/frontend/src/components/EvaluationInfo/EvaluationInfo.js +++ b/frontend/src/components/EvaluationInfo/EvaluationInfo.js @@ -1,5 +1,5 @@ -import React, { PropTypes } from 'react'; -import { connect } from 'react-redux'; +import React, { PropTypes } from 'react' +import { connect } from 'react-redux' const evaluationProps = [ 'ID', @@ -7,15 +7,15 @@ const evaluationProps = [ 'Priority', 'Type', 'JobID', - 'TriggeredBy', -]; + 'TriggeredBy' +] const EvaluationInfo = ({ evaluation }) => -
    -
    -
    +
    +
    +
    Evaluation Properties -
    +
    { evaluationProps.map(evalProp =>
    { evalProp }
    @@ -25,14 +25,14 @@ const EvaluationInfo = ({ evaluation }) =>
    -
    ; +
    -function mapStateToProps({ evaluation }) { - return { evaluation }; +function mapStateToProps ({ evaluation }) { + return { evaluation } } EvaluationInfo.propTypes = { - evaluation: PropTypes.object.isRequired, -}; + evaluation: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(EvaluationInfo); +export default connect(mapStateToProps)(EvaluationInfo) diff --git a/frontend/src/components/EvaluationList/EvaluationList.js b/frontend/src/components/EvaluationList/EvaluationList.js index e3ae0d43..4223637d 100644 --- a/frontend/src/components/EvaluationList/EvaluationList.js +++ b/frontend/src/components/EvaluationList/EvaluationList.js @@ -1,48 +1,48 @@ -import React, { PropTypes } from 'react'; -import NomadLink from '../NomadLink/NomadLink'; +import React, { PropTypes } from 'react' +import NomadLink from '../NomadLink/NomadLink' const EvaluationList = ({ evaluations, containerClassName }) =>
    -
    - +
    +
    - + - - - + + + - - + + { evaluations.map(evaluation => - - + + - + )}
    IDID JobTypePriorityStatusTypePriorityStatus Status DescriptionParentTriggered byParentTriggered by
    { evaluation.Type } { evaluation.Priority } { evaluation.Status } { evaluation.StatusDescription } { evaluation.TriggeredBy }
    -
    ; +
    EvaluationList.defaultProps = { evaluations: [], - containerClassName: '', -}; + containerClassName: '' +} EvaluationList.propTypes = { evaluations: PropTypes.array.isRequired, - containerClassName: PropTypes.string.isRequired, -}; + containerClassName: PropTypes.string.isRequired +} -export default EvaluationList; +export default EvaluationList diff --git a/frontend/src/components/EvaluationRaw/EvaluationRaw.js b/frontend/src/components/EvaluationRaw/EvaluationRaw.js index 523a9ab4..df8995a0 100644 --- a/frontend/src/components/EvaluationRaw/EvaluationRaw.js +++ b/frontend/src/components/EvaluationRaw/EvaluationRaw.js @@ -1,19 +1,19 @@ -import React, { PropTypes } from 'react'; -import { connect } from 'react-redux'; +import React, { PropTypes } from 'react' +import { connect } from 'react-redux' -import RawJson from '../RawJson/RawJson'; +import RawJson from '../RawJson/RawJson' const EvaluationRaw = ({ evaluation }) => -
    +
    -
    ; +
    -function mapStateToProps({ evaluation }) { - return { evaluation }; +function mapStateToProps ({ evaluation }) { + return { evaluation } } EvaluationRaw.propTypes = { - evaluation: PropTypes.object.isRequired, -}; + evaluation: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(EvaluationRaw); +export default connect(mapStateToProps)(EvaluationRaw) diff --git a/frontend/src/components/FormatBoolean/FormatBoolean.js b/frontend/src/components/FormatBoolean/FormatBoolean.js index 452e968a..b25abab5 100644 --- a/frontend/src/components/FormatBoolean/FormatBoolean.js +++ b/frontend/src/components/FormatBoolean/FormatBoolean.js @@ -1,5 +1,5 @@ -import React, { PropTypes } from 'react'; -import { Glyphicon } from 'react-bootstrap'; +import React, { PropTypes } from 'react' +import { Glyphicon } from 'react-bootstrap' const FormatBoolean = ({ title, @@ -10,28 +10,28 @@ const FormatBoolean = ({ trueText, falseText, falseIcon, - trueIcon, + trueIcon }) => { - let colorClass; - let icon; - let text; + let colorClass + let icon + let text if (withColor) { - colorClass = value ? 'text-success' : 'text-danger'; + colorClass = value ? 'text-success' : 'text-danger' } if (withIcon) { - icon = ; + icon = } if (withText) { - text = { value ? trueText : falseText }; + text = { value ? trueText : falseText } } return ( { icon } { text } - ); -}; + ) +} FormatBoolean.defaultProps = { value: null, @@ -45,8 +45,8 @@ FormatBoolean.defaultProps = { trueIcon: 'ok', falseText: 'no', - falseIcon: 'remove', -}; + falseIcon: 'remove' +} FormatBoolean.propTypes = { value: PropTypes.bool.isRequired, @@ -60,7 +60,7 @@ FormatBoolean.propTypes = { trueIcon: PropTypes.string.isRequired, falseText: PropTypes.string.isRequired, - falseIcon: PropTypes.string.isRequired, -}; + falseIcon: PropTypes.string.isRequired +} -export default FormatBoolean; +export default FormatBoolean diff --git a/frontend/src/components/FormatTime/FormatTime.js b/frontend/src/components/FormatTime/FormatTime.js index 42a7cc83..0aab7d97 100644 --- a/frontend/src/components/FormatTime/FormatTime.js +++ b/frontend/src/components/FormatTime/FormatTime.js @@ -1,44 +1,44 @@ -import React, { Component, PropTypes } from 'react'; -import ReactTooltip from 'react-tooltip'; +import React, { Component, PropTypes } from 'react' +import ReactTooltip from 'react-tooltip' // eslint-disable-next-line no-unused-vars -import momentDurationFormat from 'moment-duration-format'; -import moment from 'moment'; -import getMoment from '../../helpers/time'; +import momentDurationFormat from 'moment-duration-format' +import moment from 'moment' +import getMoment from '../../helpers/time' class FormatTime extends Component { - getTimeDiff(time, now) { + getTimeDiff (time, now) { if (this.props.durationInterval && this.props.durationFormat) { return moment .duration(time.diff(now), this.props.durationInterval) - .format(this.props.durationFormat, { forceLength: true }); + .format(this.props.durationFormat, { forceLength: true }) } - return time.from(now, true); + return time.from(now, true) } - render() { - const time = getMoment(this.props.time); - const now = getMoment(this.props.now); - const format = this.props.timeFormat; + render () { + const time = getMoment(this.props.time) + const now = getMoment(this.props.now) + const format = this.props.timeFormat if (this.props.display === 'relative') { return ( { time.format(format) } - + {this.getTimeDiff(time, now)} - ); + ) } return ( { this.getTimeDiff(time, now) } - { time.format(format) } + { time.format(format) } - ); + ) } } @@ -48,20 +48,20 @@ FormatTime.defaultProps = { display: 'relative', timeFormat: 'DD-MM-YYYY H:mm:ss', durationInterval: null, - durationFormat: null, -}; + durationFormat: null +} FormatTime.propTypes = { time: PropTypes.number.isRequired, now: PropTypes.oneOfType([ PropTypes.string, - PropTypes.number, + PropTypes.number ]), identifier: PropTypes.string.isRequired, display: PropTypes.string.isRequired, timeFormat: PropTypes.string.isRequired, durationInterval: PropTypes.string, - durationFormat: PropTypes.string, -}; + durationFormat: PropTypes.string +} -export default FormatTime; +export default FormatTime diff --git a/frontend/src/components/JobAllocations/JobAllocations.js b/frontend/src/components/JobAllocations/JobAllocations.js index 60ac2677..022e4374 100644 --- a/frontend/src/components/JobAllocations/JobAllocations.js +++ b/frontend/src/components/JobAllocations/JobAllocations.js @@ -1,46 +1,46 @@ -import React, { PureComponent, PropTypes } from 'react'; -import { connect } from 'react-redux'; -import AllocationList from '../AllocationList/AllocationList'; +import React, { PureComponent, PropTypes } from 'react' +import { connect } from 'react-redux' +import AllocationList from '../AllocationList/AllocationList' class JobAllocations extends PureComponent { - render() { - const jobId = this.props.params.jobId; + render () { + const jobId = this.props.params.jobId const allocs = this.props.allocations.filter(allocation => allocation.JobID === jobId - ); + ) return ( -
    +
    - ); + ) } } -function mapStateToProps({ allocations, nodes }) { - return { allocations, nodes }; +function mapStateToProps ({ allocations, nodes }) { + return { allocations, nodes } } JobAllocations.defaultProps = { allocations: [], nodes: [], params: {}, - location: {}, -}; + location: {} +} JobAllocations.propTypes = { allocations: PropTypes.array.isRequired, params: PropTypes.object.isRequired, nodes: PropTypes.array.isRequired, - location: PropTypes.object.isRequired, -}; + location: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(JobAllocations); +export default connect(mapStateToProps)(JobAllocations) diff --git a/frontend/src/components/JobEvaluations/JobEvaluations.js b/frontend/src/components/JobEvaluations/JobEvaluations.js index 2be42d9f..46d7ef7b 100644 --- a/frontend/src/components/JobEvaluations/JobEvaluations.js +++ b/frontend/src/components/JobEvaluations/JobEvaluations.js @@ -1,34 +1,34 @@ -import React, { PureComponent, PropTypes } from 'react'; -import { connect } from 'react-redux'; -import EvaluationList from '../EvaluationList/EvaluationList'; +import React, { PureComponent, PropTypes } from 'react' +import { connect } from 'react-redux' +import EvaluationList from '../EvaluationList/EvaluationList' class JobEvaluations extends PureComponent { - render() { - const jobId = this.props.params.jobId; - const evals = this.props.evaluations.filter(evaluation => evaluation.JobID === jobId); + render () { + const jobId = this.props.params.jobId + const evals = this.props.evaluations.filter(evaluation => evaluation.JobID === jobId) return ( -
    - +
    +
    - ); + ) } } -function mapStateToProps({ evaluations }) { - return { evaluations }; +function mapStateToProps ({ evaluations }) { + return { evaluations } } JobEvaluations.defaultProps = { evaluations: [], - params: {}, -}; + params: {} +} JobEvaluations.propTypes = { evaluations: PropTypes.array.isRequired, - params: PropTypes.object.isRequired, -}; + params: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(JobEvaluations); +export default connect(mapStateToProps)(JobEvaluations) diff --git a/frontend/src/components/JobInfo/JobInfo.js b/frontend/src/components/JobInfo/JobInfo.js index 09cb6a3a..df69b5bf 100644 --- a/frontend/src/components/JobInfo/JobInfo.js +++ b/frontend/src/components/JobInfo/JobInfo.js @@ -1,19 +1,19 @@ -import Paper from 'material-ui/Paper'; -import React, { Component, PropTypes } from 'react'; -import { connect } from 'react-redux'; -import NomadLink from '../NomadLink/NomadLink'; -import TableHelper from '../TableHelper/TableHelper'; -import MetaPayload from '../MetaPayload/MetaPayload'; -import ConstraintTable from '../ConstraintTable/ConstraintTable'; +import Paper from 'material-ui/Paper' +import React, { Component, PropTypes } from 'react' +import { connect } from 'react-redux' +import NomadLink from '../NomadLink/NomadLink' +import TableHelper from '../TableHelper/TableHelper' +import MetaPayload from '../MetaPayload/MetaPayload' +import ConstraintTable from '../ConstraintTable/ConstraintTable' -const jobProps = ['ID', 'Name', 'Region', 'Datacenters', 'Status', 'Priority']; +const jobProps = ['ID', 'Name', 'Region', 'Datacenters', 'Status', 'Priority'] class JobInfo extends Component { - render() { - const tasks = []; - const job = this.props.job; - const jobMetaBag = job.Meta || {}; + render () { + const tasks = [] + const job = this.props.job + const jobMetaBag = job.Meta || {} // Build the task groups table const taskGroups = job.TaskGroups.map((taskGroup) => { @@ -36,11 +36,11 @@ class JobInfo extends Component { { task.Resources.DiskMB } - ); - return null; - }); + ) + return null + }) - const taskGroupMeta = taskGroup.Meta || {}; + const taskGroupMeta = taskGroup.Meta || {} return ( @@ -54,48 +54,48 @@ class JobInfo extends Component { { taskGroup.RestartPolicy.Mode } - ); - }); + ) + }) return ( -
    -
    - +
    +
    + Job Properties -
    +
    { jobProps.map((jobProp) => { - let jobPropValue = this.props.job[jobProp]; + let jobPropValue = this.props.job[jobProp] if (Array.isArray(jobPropValue)) { - jobPropValue = jobPropValue.join(', '); + jobPropValue = jobPropValue.join(', ') } - const result = []; - result.push(
    { jobProp }
    ); - result.push(
    { jobPropValue }
    ); + const result = [] + result.push(
    { jobProp }
    ) + result.push(
    { jobPropValue }
    ) - return result; + return result }, this)}
    -
    +
    Meta Properties - +
    -
    -
    +
    +
    Constraints
    -
    -
    +
    +
    Task Groups { (taskGroups.length > 0) ? @@ -104,12 +104,12 @@ class JobInfo extends Component {
    -
    -
    +
    +
    Tasks { (tasks.length > 0) ? @@ -118,25 +118,24 @@ class JobInfo extends Component {
    - ); + ) } } JobInfo.defaultProps = { job: { - constraints: [], + constraints: [] }, allocations: {}, - evaluations: {}, -}; - + evaluations: {} +} -function mapStateToProps({ job, allocations, evaluations }) { - return { job, allocations, evaluations }; +function mapStateToProps ({ job, allocations, evaluations }) { + return { job, allocations, evaluations } } JobInfo.propTypes = { - job: PropTypes.object.isRequired, -}; + job: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(JobInfo); +export default connect(mapStateToProps)(JobInfo) diff --git a/frontend/src/components/JobRaw/JobRaw.js b/frontend/src/components/JobRaw/JobRaw.js index f773ba34..ea0a4547 100644 --- a/frontend/src/components/JobRaw/JobRaw.js +++ b/frontend/src/components/JobRaw/JobRaw.js @@ -1,19 +1,19 @@ -import React, { PropTypes } from 'react'; -import { connect } from 'react-redux'; +import React, { PropTypes } from 'react' +import { connect } from 'react-redux' -import RawJson from '../RawJson/RawJson'; +import RawJson from '../RawJson/RawJson' const JobRaw = ({ job }) => -
    +
    -
    ; +
    -function mapStateToProps({ job }) { - return { job }; +function mapStateToProps ({ job }) { + return { job } } JobRaw.propTypes = { - job: PropTypes.object.isRequired, -}; + job: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(JobRaw); +export default connect(mapStateToProps)(JobRaw) diff --git a/frontend/src/components/JobTaskGroups/JobTaskGroups.js b/frontend/src/components/JobTaskGroups/JobTaskGroups.js index 3ade824d..6587591b 100644 --- a/frontend/src/components/JobTaskGroups/JobTaskGroups.js +++ b/frontend/src/components/JobTaskGroups/JobTaskGroups.js @@ -1,54 +1,54 @@ -import React, { PropTypes } from 'react'; -import { connect } from 'react-redux'; -import NomadLink from '../NomadLink/NomadLink'; -import TableHelper from '../TableHelper/TableHelper'; -import RawJson from '../RawJson/RawJson'; -import MetaPayload from '../MetaPayload/MetaPayload'; +import React, { PropTypes } from 'react' +import { connect } from 'react-redux' +import NomadLink from '../NomadLink/NomadLink' +import TableHelper from '../TableHelper/TableHelper' +import RawJson from '../RawJson/RawJson' +import MetaPayload from '../MetaPayload/MetaPayload' const taskGroupHeaders = [ 'ID', 'Name', 'Count', 'Meta', - 'Restart Policy', -]; + 'Restart Policy' +] const JobTaskGroups = ({ job, location }) => { - const taskGroups = []; + const taskGroups = [] job.TaskGroups.forEach((taskGroup) => { taskGroups.push( - + { taskGroup.Name } { taskGroup.Count } { taskGroup.RestartPolicy.Mode } - ); - }); + ) + }) - let taskGroupId = location.query.taskGroupId; + let taskGroupId = location.query.taskGroupId // Auto-select first task group if only one is available. if (!taskGroupId && job.TaskGroups.length === 1) { - taskGroupId = job.TaskGroups[0].ID; + taskGroupId = job.TaskGroups[0].ID } return ( -
    -
    -
    +
    +
    +
    Task Groups { (taskGroups.length > 0) ? : null }
    -
    +
    Task Group: { taskGroupId } { job.TaskGroups .filter(taskGroup => taskGroup.ID === taskGroupId) @@ -58,16 +58,16 @@ const JobTaskGroups = ({ job, location }) => {
    - ); -}; + ) +} -function mapStateToProps({ job }) { - return { job }; +function mapStateToProps ({ job }) { + return { job } } JobTaskGroups.propTypes = { job: PropTypes.object.isRequired, - location: PropTypes.object.isRequired, -}; + location: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(JobTaskGroups); +export default connect(mapStateToProps)(JobTaskGroups) diff --git a/frontend/src/components/JobTasks/JobTasks.js b/frontend/src/components/JobTasks/JobTasks.js index da9b67cb..f2d38de1 100644 --- a/frontend/src/components/JobTasks/JobTasks.js +++ b/frontend/src/components/JobTasks/JobTasks.js @@ -1,8 +1,8 @@ -import React, { PropTypes } from 'react'; -import { connect } from 'react-redux'; -import NomadLink from '../NomadLink/NomadLink'; -import TableHelper from '../TableHelper/TableHelper'; -import RawJson from '../RawJson/RawJson'; +import React, { PropTypes } from 'react' +import { connect } from 'react-redux' +import NomadLink from '../NomadLink/NomadLink' +import TableHelper from '../TableHelper/TableHelper' +import RawJson from '../RawJson/RawJson' const taskHeaders = [ 'ID', @@ -11,11 +11,11 @@ const taskHeaders = [ 'Driver', 'CPU', 'Memory', - 'Disk', -]; + 'Disk' +] const JobTasks = ({ job, location }) => { - const tasks = []; + const tasks = [] job.TaskGroups.forEach((taskGroup) => { taskGroup.Tasks.forEach((task) => { tasks.push( @@ -25,7 +25,7 @@ const JobTasks = ({ job, location }) => { taskId={ task.ID } taskGroupId={ taskGroup.ID } jobId={ job.ID } - short="true" + short='true' /> {task.Name} @@ -39,37 +39,37 @@ const JobTasks = ({ job, location }) => { { task.Resources.MemoryMB } { task.Resources.DiskMB } - ); - }); - }); + ) + }) + }) - let taskGroupId = location.query.taskGroupId; - let taskId = location.query.taskId; + let taskGroupId = location.query.taskGroupId + let taskId = location.query.taskId // Auto-select first task if only one is available. if (!taskGroupId && !taskId && tasks.length === 1) { job.TaskGroups.forEach((taskGroup) => { taskGroup.Tasks.forEach((task) => { - taskGroupId = taskGroup.ID; - taskId = task.ID; - }); - }); + taskGroupId = taskGroup.ID + taskId = task.ID + }) + }) } return ( -
    -
    -
    +
    +
    +
    Tasks { (tasks.length > 0) ? : null }
    -
    +
    Task: { (taskGroupId && taskId) ? `${taskGroupId}/${taskId}` : null} { job.TaskGroups .filter(taskGroup => taskGroup.ID === taskGroupId) @@ -81,16 +81,16 @@ const JobTasks = ({ job, location }) => {
    - ); -}; + ) +} -function mapStateToProps({ job }) { - return { job }; +function mapStateToProps ({ job }) { + return { job } } JobTasks.propTypes = { job: PropTypes.object.isRequired, - location: PropTypes.object.isRequired, -}; + location: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(JobTasks); +export default connect(mapStateToProps)(JobTasks) diff --git a/frontend/src/components/MetaPayload/MetaPayload.js b/frontend/src/components/MetaPayload/MetaPayload.js index f92a172d..b9b8d716 100644 --- a/frontend/src/components/MetaPayload/MetaPayload.js +++ b/frontend/src/components/MetaPayload/MetaPayload.js @@ -1,47 +1,47 @@ -import React, { Component, PropTypes } from 'react'; -import ReactTooltip from 'react-tooltip'; -import uuid from 'node-uuid'; +import React, { Component, PropTypes } from 'react' +import ReactTooltip from 'react-tooltip' +import uuid from 'node-uuid' class MetaPayload extends Component { - render() { - const metaBag = this.props.metaBag || {}; - const dtWithClass = this.props.dtWithClass; - const sortKeys = this.props.sortKeys; - const asTooltip = this.props.asTooltip; + render () { + const metaBag = this.props.metaBag || {} + const dtWithClass = this.props.dtWithClass + const sortKeys = this.props.sortKeys + const asTooltip = this.props.asTooltip - let keys = Object.keys(metaBag || {}); + let keys = Object.keys(metaBag || {}) if (keys.length === 0) { - return (
    - No data found -
    ); + return (
    - No data found -
    ) } - const identifier = uuid.v1(); - const meta = []; - let metaTag = null; + const identifier = uuid.v1() + const meta = [] + let metaTag = null if (sortKeys) { - keys = keys.sort(); + keys = keys.sort() } keys.forEach((key) => { - meta.push(
    { key }
    ); - meta.push(
    { metaBag[key] }
    ); - }); + meta.push(
    { key }
    ) + meta.push(
    { metaBag[key] }
    ) + }) if (meta.length > 0) { - metaTag =
    { meta }
    ; + metaTag =
    { meta }
    } if (asTooltip) { return (
    { metaTag } - { keys.length } keys + { keys.length } keys
    - ); + ) } - return metaTag; + return metaTag } } @@ -49,14 +49,14 @@ MetaPayload.defaultProps = { metaBag: {}, dtWithClass: 'default', sortKeys: true, - asTooltip: false, -}; + asTooltip: false +} MetaPayload.propTypes = { metaBag: PropTypes.object, dtWithClass: PropTypes.string.isRequired, sortKeys: PropTypes.bool.isRequired, - asTooltip: PropTypes.bool.isRequired, -}; + asTooltip: PropTypes.bool.isRequired +} -export default MetaPayload; +export default MetaPayload diff --git a/frontend/src/components/NodeStatus/NodeStatus.js b/frontend/src/components/NodeStatus/NodeStatus.js index 59fbb032..b8bc913f 100644 --- a/frontend/src/components/NodeStatus/NodeStatus.js +++ b/frontend/src/components/NodeStatus/NodeStatus.js @@ -1,28 +1,28 @@ -import React, { PropTypes } from 'react'; -import FormatBoolean from '../FormatBoolean/FormatBoolean'; +import React, { PropTypes } from 'react' +import FormatBoolean from '../FormatBoolean/FormatBoolean' const NodeStatus = ({ value }) => { switch (value) { case 'initializing': - return (initializing); + return (initializing) case 'ready': - return (); + return () case 'down': - return (); + return () default: - return ({value}); + return ({value}) } -}; +} NodeStatus.defaultProps = { - value: null, -}; + value: null +} NodeStatus.propTypes = { - value: PropTypes.string.isRequired, -}; + value: PropTypes.string.isRequired +} -export default NodeStatus; +export default NodeStatus diff --git a/frontend/src/components/NomadLink/NomadLink.js b/frontend/src/components/NomadLink/NomadLink.js index 48e5ca11..fbba588a 100644 --- a/frontend/src/components/NomadLink/NomadLink.js +++ b/frontend/src/components/NomadLink/NomadLink.js @@ -1,155 +1,155 @@ -import React, { Component, PropTypes } from 'react'; -import { Link } from 'react-router'; -import shortUUID from '../../helpers/uuid'; +import React, { Component, PropTypes } from 'react' +import { Link } from 'react-router' +import shortUUID from '../../helpers/uuid' -const nodeIdToNameCache = {}; +const nodeIdToNameCache = {} -function NomadLinkException(message) { - this.message = message; - this.name = 'NomadLinkException'; +function NomadLinkException (message) { + this.message = message + this.name = 'NomadLinkException' } export default class NomadLink extends Component { - findNodeNameById(nodeId) { + findNodeNameById (nodeId) { if (nodeId in nodeIdToNameCache) { - return nodeIdToNameCache[nodeId]; + return nodeIdToNameCache[nodeId] } const r = Object.keys(this.props.nodeList) .filter(node => this.props.nodeList[node].ID === nodeId - ); + ) if (r.length !== 0) { - nodeIdToNameCache[nodeId] = this.props.nodeList[r].Name; + nodeIdToNameCache[nodeId] = this.props.nodeList[r].Name } else { - nodeIdToNameCache[nodeId] = false; + nodeIdToNameCache[nodeId] = false } - return nodeIdToNameCache[nodeId]; + return nodeIdToNameCache[nodeId] } - render() { - const short = this.props.short === 'true'; - const linkAppend = this.props.linkAppend || ''; + render () { + const short = this.props.short === 'true' + const linkAppend = this.props.linkAppend || '' - let children = this.props.children; - const linkProps = Object.assign({}, this.props); + let children = this.props.children + const linkProps = Object.assign({}, this.props) Object.keys(linkProps) .filter(key => key.endsWith('Id')) .forEach((key) => { - delete linkProps[key]; - }); + delete linkProps[key] + }) - delete linkProps.short; - delete linkProps.nodeList; - delete linkProps.linkAppend; + delete linkProps.short + delete linkProps.nodeList + delete linkProps.linkAppend // member if (this.props.memberId !== undefined) { - const memberId = this.props.memberId; + const memberId = this.props.memberId if (children === undefined) { - children = short ? shortUUID(memberId) : memberId; + children = short ? shortUUID(memberId) : memberId } - return ({ children }); + return ({ children }) } // node if (this.props.nodeId !== undefined) { - const nodeId = this.props.nodeId; + const nodeId = this.props.nodeId if (children === undefined) { if (this.props.nodeList) { - children = this.findNodeNameById(this.props.nodeId); + children = this.findNodeNameById(this.props.nodeId) } if (!children) { - children = short ? shortUUID(nodeId) : nodeId; + children = short ? shortUUID(nodeId) : nodeId } } - return ({ children }); + return ({ children }) } // eval if (this.props.evalId !== undefined) { - const evalId = this.props.evalId; + const evalId = this.props.evalId if (children === undefined) { - children = short ? shortUUID(evalId) : evalId; + children = short ? shortUUID(evalId) : evalId } - return ({ children }); + return ({ children }) } // alloc if (this.props.allocId !== undefined) { - const allocId = this.props.allocId; + const allocId = this.props.allocId if (children === undefined) { - children = short ? shortUUID(allocId) : allocId; + children = short ? shortUUID(allocId) : allocId } - return ({ children }); + return ({ children }) } // tasks if (this.props.taskId !== undefined) { if (this.props.jobId !== undefined && this.props.taskGroupId !== undefined) { - const jobId = this.props.jobId; - const jobIdUrl = encodeURIComponent(jobId); - const taskGroupId = this.props.taskGroupId; - const taskId = this.props.taskId; + const jobId = this.props.jobId + const jobIdUrl = encodeURIComponent(jobId) + const taskGroupId = this.props.taskGroupId + const taskId = this.props.taskId if (children === undefined) { - children = short ? shortUUID(taskId) : taskId; + children = short ? shortUUID(taskId) : taskId } return ( { children } - ); + ) } - throw new NomadLinkException('NomadLink: You must also provide taskGroupId and jobId for task links!'); + throw new NomadLinkException('NomadLink: You must also provide taskGroupId and jobId for task links!') } // taskGroup (must be after task) if (this.props.taskGroupId !== undefined) { if (this.props.jobId !== undefined) { - const jobId = this.props.jobId; - const jobIdUrl = encodeURIComponent(jobId); - const taskGroupId = this.props.taskGroupId; + const jobId = this.props.jobId + const jobIdUrl = encodeURIComponent(jobId) + const taskGroupId = this.props.taskGroupId if (children === undefined) { - children = short ? shortUUID(taskGroupId) : taskGroupId; + children = short ? shortUUID(taskGroupId) : taskGroupId } return ( { children } - ); + ) } - throw new NomadLinkException('NomadLink: You must also provide jobId for taskGroup links!'); + throw new NomadLinkException('NomadLink: You must also provide jobId for taskGroup links!') } // job (must be after task & taskGroup if (this.props.jobId !== undefined) { - const jobId = this.props.jobId; - const jobIdUrl = encodeURIComponent(jobId); + const jobId = this.props.jobId + const jobIdUrl = encodeURIComponent(jobId) if (children === undefined) { - children = short ? shortUUID(jobId) : jobId; + children = short ? shortUUID(jobId) : jobId } - return ({ children }); + return ({ children }) } - console.log(this.props); - throw new NomadLinkException('NomadLink: Unable to generate a link (check console for props)'); + console.log(this.props) + throw new NomadLinkException('NomadLink: Unable to generate a link (check console for props)') } } @@ -159,7 +159,7 @@ NomadLink.propTypes = { children: PropTypes.oneOfType([ PropTypes.array, PropTypes.string, - React.PropTypes.node, + React.PropTypes.node ]), memberId: PropTypes.string, nodeId: PropTypes.string, @@ -168,5 +168,5 @@ NomadLink.propTypes = { taskId: PropTypes.string, jobId: PropTypes.string, linkAppend: PropTypes.string, - taskGroupId: PropTypes.string, -}; + taskGroupId: PropTypes.string +} diff --git a/frontend/src/components/Progressbar/Progressbar.js b/frontend/src/components/Progressbar/Progressbar.js index 6b117349..a34e5a78 100644 --- a/frontend/src/components/Progressbar/Progressbar.js +++ b/frontend/src/components/Progressbar/Progressbar.js @@ -1,9 +1,9 @@ -import React, { Component, PropTypes } from 'react'; -import { ProgressBar } from 'react-bootstrap'; +import React, { Component, PropTypes } from 'react' +import { ProgressBar } from 'react-bootstrap' class Progressbar extends Component { - colorIndex(index) { + colorIndex (index) { return { // client status ready: 'success', @@ -31,22 +31,22 @@ class Progressbar extends Component { starting: 'warning', queued: 'info', failed: 'danger', - lost: 'danger', - }[index]; + lost: 'danger' + }[index] } - render() { - const keys = Object.keys(this.props.data); - const normalizedValues = {}; - keys.forEach(key => (normalizedValues[key.toLowerCase()] = this.props.data[key])); - const normalizedKeys = keys.map(string => string.toLowerCase()); + render () { + const keys = Object.keys(this.props.data) + const normalizedValues = {} + keys.forEach(key => (normalizedValues[key.toLowerCase()] = this.props.data[key])) + const normalizedKeys = keys.map(string => string.toLowerCase()) const sum = normalizedKeys.reduce((previous, currentValue) => { - return previous + normalizedValues[currentValue]; - }, 0); + return previous + normalizedValues[currentValue] + }, 0) return ( -
    -
    +
    +
    { this.props.title }
    @@ -59,7 +59,7 @@ class Progressbar extends Component { now={ normalizedValues[index] } key={ index } /> - ); + ) })} @@ -69,17 +69,17 @@ class Progressbar extends Component { { index } ({ normalizedValues[index] }) - ); + ) })}
    - ); + ) } } Progressbar.propTypes = { data: PropTypes.object.isRequired, - title: PropTypes.string.isRequired, -}; + title: PropTypes.string.isRequired +} -export default Progressbar; +export default Progressbar diff --git a/frontend/src/components/RawJson/RawJson.js b/frontend/src/components/RawJson/RawJson.js index 7f962e8c..493aa977 100644 --- a/frontend/src/components/RawJson/RawJson.js +++ b/frontend/src/components/RawJson/RawJson.js @@ -1,41 +1,41 @@ -import React, { Component, PropTypes } from 'react'; -import JSONFormatter from 'json-formatter-js'; +import React, { Component, PropTypes } from 'react' +import JSONFormatter from 'json-formatter-js' class Json extends Component { - componentDidMount() { + componentDidMount () { const formatter = new JSONFormatter(this.props.json, 2, { hoverPreviewEnabled: true, hoverPreviewArrayCount: 100, - hoverPreviewFieldCount: 5, - }); - this.json.appendChild(formatter.render()); + hoverPreviewFieldCount: 5 + }) + this.json.appendChild(formatter.render()) } - componentDidUpdate() { + componentDidUpdate () { const formatter = new JSONFormatter(this.props.json, 2, { hoverPreviewEnabled: true, hoverPreviewArrayCount: 100, - hoverPreviewFieldCount: 5, - }); + hoverPreviewFieldCount: 5 + }) // Remove the old JSON if (this.json.hasChildNodes()) { - this.json.removeChild(this.json.childNodes[0]); + this.json.removeChild(this.json.childNodes[0]) } // Add the new JSON - this.json.appendChild(formatter.render()); + this.json.appendChild(formatter.render()) } - render() { + render () { return ( -
    { this.json = c; } }>
    - ); +
    { this.json = c } }>
    + ) } } Json.propTypes = { - json: PropTypes.object.isRequired, -}; + json: PropTypes.object.isRequired +} -export default Json; +export default Json diff --git a/frontend/src/components/ServerInfo/ServerInfo.js b/frontend/src/components/ServerInfo/ServerInfo.js index 8140a113..029caa52 100644 --- a/frontend/src/components/ServerInfo/ServerInfo.js +++ b/frontend/src/components/ServerInfo/ServerInfo.js @@ -1,35 +1,35 @@ -import React, { PropTypes } from 'react'; -import { connect } from 'react-redux'; -import TableHelper from '../TableHelper/TableHelper'; +import React, { PropTypes } from 'react' +import { connect } from 'react-redux' +import TableHelper from '../TableHelper/TableHelper' const memberProps = [ 'ID', 'Name', 'Address', 'Port', - 'Status', -]; + 'Status' +] const ServerInfo = ({ member }) => { - const tags = member.Tags; + const tags = member.Tags const memberTags = Object.keys(tags).map((key) => { - const name = key; - const value = tags[key]; + const name = key + const value = tags[key] return ( { name } { value } - ); - }); + ) + }) return ( -
    -
    +
    +
    Server Properties -
    +
    { memberProps.map(memberProp =>
    { memberProp }
    @@ -40,20 +40,20 @@ const ServerInfo = ({ member }) => {
    Server Tags { (memberTags.length > 0) ? - + : null }
    - ); -}; + ) +} -function mapStateToProps({ member }) { - return { member }; +function mapStateToProps ({ member }) { + return { member } } ServerInfo.propTypes = { - member: PropTypes.object.isRequired, -}; + member: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(ServerInfo); +export default connect(mapStateToProps)(ServerInfo) diff --git a/frontend/src/components/ServerRaw/ServerRaw.js b/frontend/src/components/ServerRaw/ServerRaw.js index cef041b6..84c7b885 100644 --- a/frontend/src/components/ServerRaw/ServerRaw.js +++ b/frontend/src/components/ServerRaw/ServerRaw.js @@ -1,19 +1,19 @@ -import React, { PropTypes } from 'react'; -import { connect } from 'react-redux'; +import React, { PropTypes } from 'react' +import { connect } from 'react-redux' -import RawJson from '../RawJson/RawJson'; +import RawJson from '../RawJson/RawJson' const ServerRaw = ({ member }) => -
    +
    -
    ; +
    -function mapStateToProps({ member }) { - return { member }; +function mapStateToProps ({ member }) { + return { member } } ServerRaw.propTypes = { - member: PropTypes.object.isRequired, -}; + member: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(ServerRaw); +export default connect(mapStateToProps)(ServerRaw) diff --git a/frontend/src/components/TableHelper/TableHelper.js b/frontend/src/components/TableHelper/TableHelper.js index 370515dd..60c62de6 100644 --- a/frontend/src/components/TableHelper/TableHelper.js +++ b/frontend/src/components/TableHelper/TableHelper.js @@ -1,5 +1,5 @@ -import React, { PropTypes } from 'react'; -import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow } from 'material-ui/Table'; +import React, { PropTypes } from 'react' +import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow } from 'material-ui/Table' const TableHelper = ({ classes, headers, body }) => @@ -11,12 +11,12 @@ const TableHelper = ({ classes, headers, body }) => { body } -
    ; + TableHelper.propTypes = { classes: PropTypes.string.isRequired, headers: PropTypes.array.isRequired, - body: PropTypes.array.isRequired, -}; + body: PropTypes.array.isRequired +} -export default TableHelper; +export default TableHelper diff --git a/frontend/src/components/Tabs/Tabs.js b/frontend/src/components/Tabs/Tabs.js index 6a790ef8..5b9659c1 100644 --- a/frontend/src/components/Tabs/Tabs.js +++ b/frontend/src/components/Tabs/Tabs.js @@ -1,14 +1,14 @@ -import React, { PropTypes } from 'react'; -import { Link } from 'react-router'; +import React, { PropTypes } from 'react' +import { Link } from 'react-router' const Tabs = ({ children, tabs, tabSlug, basePath }) =>
    -
      +
        {tabs.map(tab => -
      • +
      • { tab.name } @@ -16,16 +16,16 @@ const Tabs = ({ children, tabs, tabSlug, basePath }) =>
      • ) }
      -
      +
      {children}
      -
      ; +
    Tabs.propTypes = { tabs: PropTypes.array.isRequired, tabSlug: PropTypes.string.isRequired, basePath: PropTypes.string.isRequired, - children: PropTypes.object.isRequired, -}; + children: PropTypes.object.isRequired +} -export default Tabs; +export default Tabs diff --git a/frontend/src/components/Topbar/Topbar.js b/frontend/src/components/Topbar/Topbar.js index be865515..d1d4f3c8 100644 --- a/frontend/src/components/Topbar/Topbar.js +++ b/frontend/src/components/Topbar/Topbar.js @@ -1,63 +1,66 @@ -import FontIcon from 'material-ui/FontIcon'; -import React, { PureComponent } from 'react'; -import AppBar from 'material-ui/AppBar'; -import { Link, withRouter } from 'react-router'; -import {Tabs, Tab} from 'material-ui/Tabs'; -import Slider from 'material-ui/Slider'; +import React, { PureComponent, PropTypes } from 'react' +import AppBar from 'material-ui/AppBar' +import { withRouter } from 'react-router' +import {Tabs, Tab} from 'material-ui/Tabs' class Topbar extends PureComponent { - handleActive = (tab) => { - this.props.router.push(tab.props['data-route']); + handleActive (tab) { + this.props.router.push(tab.props['data-route']) } - getActiveTab = () => { - const location = this.props.location; + getActiveTab () { + const location = this.props.location if (location.pathname.startsWith('/cluster')) { - return 'cluster'; + return 'cluster' } if (location.pathname.startsWith('/jobs')) { - return 'jobs'; + return 'jobs' } if (location.pathname.startsWith('/allocations')) { - return 'allocations'; + return 'allocations' } if (location.pathname.startsWith('/evaluations')) { - return 'evaluations'; + return 'evaluations' } if (location.pathname.startsWith('/clients')) { - return 'clients'; + return 'clients' } if (location.pathname.startsWith('/servers')) { - return 'servers'; + return 'servers' } return 'cluster' } - render() { + render () { return (
    - + - - - - - - + + + + + +
    - ); + ) } } -const TopbarWithRouter = withRouter(Topbar); +Topbar.propTypes = { + router: PropTypes.object.isRequired, + location: PropTypes.object.isRequired +} + +const TopbarWithRouter = withRouter(Topbar) -export default TopbarWithRouter; +export default TopbarWithRouter diff --git a/frontend/src/components/ViewAllocationTopbar/ViewAllocationTopbar.js b/frontend/src/components/ViewAllocationTopbar/ViewAllocationTopbar.js index 478c1792..e946a84d 100644 --- a/frontend/src/components/ViewAllocationTopbar/ViewAllocationTopbar.js +++ b/frontend/src/components/ViewAllocationTopbar/ViewAllocationTopbar.js @@ -1,65 +1,69 @@ -import FontIcon from 'material-ui/FontIcon'; -import React, { PureComponent } from 'react'; -import Slider from 'material-ui/Slider'; -import { BottomNavigation, BottomNavigationItem } from 'material-ui/BottomNavigation'; -import { Link, withRouter } from 'react-router'; +import FontIcon from 'material-ui/FontIcon' +import React, { PureComponent, PropTypes } from 'react' +import { BottomNavigation, BottomNavigationItem } from 'material-ui/BottomNavigation' +import { withRouter } from 'react-router' -const infoIcon = info_outline; -const filesIcon = storage; -const logsIcon = subject; -const rawIcon = highlight; +const infoIcon = info_outline +const filesIcon = storage +const logsIcon = subject +const rawIcon = highlight class _ViewAllocationTopbar extends PureComponent { - handleActive = (tab) => { - let path = location.pathname.split('/'); - path.pop(); + handleActive (tab) { + let path = location.pathname.split('/') + path.pop() path = path.join('/') - this.props.router.push(path + '/' + tab); + this.props.router.push(path + '/' + tab) } - getActiveTab = () => { - const location = this.props.location; - const end = location.pathname.split('/').pop(); + getActiveTab () { + const location = this.props.location + const end = location.pathname.split('/').pop() if (end.startsWith('info')) { - return 0; + return 0 } if (location.query.path && location.query.path.indexOf('alloc/logs') !== -1) { - return 2; + return 2 } if (end.startsWith('files')) { - return 1; + return 1 } if (end.startsWith('raw')) { - return 3; + return 3 } - return 0; + return 0 } - getStyle() { + getStyle () { return { borderBottom: '1px solid #e0e0e0', - marginBottom: 10, + marginBottom: 10 } } - render() { + render () { return ( - this.handleActive('info') } /> - this.handleActive('files') } /> - this.handleActive('logs') } /> - this.handleActive('raw') } /> + this.handleActive('info') } /> + this.handleActive('files') } /> + this.handleActive('logs') } /> + this.handleActive('raw') } /> - ); + ) } } -const ViewAllocationTopbar = withRouter(_ViewAllocationTopbar); +_ViewAllocationTopbar.propTypes = { + router: PropTypes.object.isRequired, + location: PropTypes.object.isRequired +} + +const ViewAllocationTopbar = withRouter(_ViewAllocationTopbar) -export default ViewAllocationTopbar; +export default ViewAllocationTopbar diff --git a/frontend/src/components/app.js b/frontend/src/components/app.js index 3e70bfbf..cca923c4 100644 --- a/frontend/src/components/app.js +++ b/frontend/src/components/app.js @@ -1,30 +1,30 @@ -import React, { PureComponent, PropTypes } from 'react'; -import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; -import injectTapEventPlugin from 'react-tap-event-plugin'; -import { green500, green800, green900 } from 'material-ui/styles/colors'; -import getMuiTheme from 'material-ui/styles/getMuiTheme'; -import Topbar from './Topbar/Topbar'; +import React, { PureComponent, PropTypes } from 'react' +import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider' +import injectTapEventPlugin from 'react-tap-event-plugin' +import { green800, green900 } from 'material-ui/styles/colors' +import getMuiTheme from 'material-ui/styles/getMuiTheme' +import Topbar from './Topbar/Topbar' const muiTheme = getMuiTheme({ palette: { - primary1Color: green500, + primary1Color: '#4b9a7d', primary2Color: green800, - primary3Color: green900, + primary3Color: green900 }, appBar: { - height: 50, - }, -}); + height: 50 + } +}) class App extends PureComponent { - constructor(props) { - super(props); + constructor (props) { + super(props) - injectTapEventPlugin(); + injectTapEventPlugin() } - render() { + render () { return (
    @@ -32,12 +32,12 @@ class App extends PureComponent { { this.props.children }
    - ); + ) } } App.propTypes = { - children: PropTypes.object.isRequired, -}; + children: PropTypes.object.isRequired +} -export default App; +export default App diff --git a/frontend/src/containers/allocation.js b/frontend/src/containers/allocation.js index a13a5eca..a060c01b 100644 --- a/frontend/src/containers/allocation.js +++ b/frontend/src/containers/allocation.js @@ -1,80 +1,80 @@ -import React, { Component, PropTypes } from 'react'; -import { connect } from 'react-redux'; -import ViewAllocationTopbar from '../components/ViewAllocationTopbar/ViewAllocationTopbar'; -import { WATCH_ALLOC, UNWATCH_ALLOC } from '../sagas/event'; +import React, { Component, PropTypes } from 'react' +import { connect } from 'react-redux' +import ViewAllocationTopbar from '../components/ViewAllocationTopbar/ViewAllocationTopbar' +import { WATCH_ALLOC, UNWATCH_ALLOC } from '../sagas/event' class Allocation extends Component { - constructor(props) { - super(props); + constructor (props) { + super(props) this.state = { tabs: [ { name: 'Info', - path: 'info', + path: 'info' }, { name: 'Files', - path: 'files', + path: 'files' }, { name: 'Logs', - path: 'logs', + path: 'logs' }, { name: 'Raw', - path: 'raw', - }, - ], - }; + path: 'raw' + } + ] + } } - componentWillMount() { + componentWillMount () { this.props.dispatch({ type: WATCH_ALLOC, - payload: this.props.params.allocId, - }); + payload: this.props.params.allocId + }) } - componentWillUnmount() { + componentWillUnmount () { this.props.dispatch({ type: UNWATCH_ALLOC, - payload: this.props.params.allocId, - }); + payload: this.props.params.allocId + }) } - render() { - if (this.props.allocation == null) return (null); - - const path = this.props.location.pathname; - const tabSlug = path.split('/').pop(); - const basePath = path.substring(0, path.lastIndexOf('/')); + render () { + if (this.props.allocation == null) { + return null + } return (
    -

    Allocation: { this.props.allocation.Name }

    +
    +

    Allocation: { this.props.allocation.Name }

    -
    +
    - { this.props.children } + { this.props.children } +
    - ); + ) } } -function mapStateToProps({ allocation }) { - return { allocation }; +function mapStateToProps ({ allocation }) { + return { allocation } } Allocation.propTypes = { dispatch: PropTypes.func.isRequired, params: PropTypes.object.isRequired, allocation: PropTypes.object.isRequired, - location: PropTypes.object.isRequired, - children: PropTypes.object.isRequired, -}; + location: PropTypes.object.isRequired, // eslint-disable-line no-unused-vars + children: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(Allocation); +export default connect(mapStateToProps)(Allocation) diff --git a/frontend/src/containers/allocations.js b/frontend/src/containers/allocations.js index 96a589bd..53751234 100644 --- a/frontend/src/containers/allocations.js +++ b/frontend/src/containers/allocations.js @@ -1,21 +1,21 @@ -import React, { Component, PropTypes } from 'react'; -import { connect } from 'react-redux'; -import AllocationList from '../components/AllocationList/AllocationList'; +import React, { Component, PropTypes } from 'react' +import { connect } from 'react-redux' +import AllocationList from '../components/AllocationList/AllocationList' class Allocations extends Component { - render() { - return ; + render () { + return } } -function mapStateToProps({ allocations, nodes }) { - return { allocations, nodes }; +function mapStateToProps ({ allocations, nodes }) { + return { allocations, nodes } } Allocations.propTypes = { - allocations: PropTypes.array.isRequired, - nodes: PropTypes.array.isRequired, -}; + allocations: PropTypes.array.isRequired, // eslint-disable-line no-unused-vars + nodes: PropTypes.array.isRequired // eslint-disable-line no-unused-vars +} -export default connect(mapStateToProps)(Allocations); +export default connect(mapStateToProps)(Allocations) diff --git a/frontend/src/containers/client.js b/frontend/src/containers/client.js index a6531753..1ba3e601 100644 --- a/frontend/src/containers/client.js +++ b/frontend/src/containers/client.js @@ -1,64 +1,64 @@ -import React, { Component, PropTypes } from 'react'; -import { connect } from 'react-redux'; -import Tabs from '../components/Tabs/Tabs'; -import { WATCH_NODE, UNWATCH_NODE } from '../sagas/event'; +import React, { Component, PropTypes } from 'react' +import { connect } from 'react-redux' +import Tabs from '../components/Tabs/Tabs' +import { WATCH_NODE, UNWATCH_NODE } from '../sagas/event' class Client extends Component { - constructor(props) { - super(props); + constructor (props) { + super(props) this.state = { tabs: [ { name: 'Info', - path: 'info', + path: 'info' }, { name: 'Allocations', - path: 'allocations', + path: 'allocations' }, { name: 'Evaluations', - path: 'evaluations', + path: 'evaluations' }, { name: 'Raw', - path: 'raw', - }, - ], - }; + path: 'raw' + } + ] + } } - componentWillMount() { + componentWillMount () { this.props.dispatch({ type: WATCH_NODE, - payload: this.props.params.nodeId, - }); + payload: this.props.params.nodeId + }) } - componentWillUnmount() { + componentWillUnmount () { this.props.dispatch({ type: UNWATCH_NODE, - payload: this.props.params.nodeId, - }); + payload: this.props.params.nodeId + }) } - render() { - if (this.props.node == null) return (null); + render () { + if (this.props.node == null) return (null) - const path = this.props.location.pathname; - const tabSlug = path.split('/').pop(); - const basePath = path.substring(0, path.lastIndexOf('/')); + const path = this.props.location.pathname + const tabSlug = path.split('/').pop() + const basePath = path.substring(0, path.lastIndexOf('/')) return ( -
    -
    -
    -
    -

    Client: { this.props.node.Name }

    +
    +
    +
    +
    +

    Client: { this.props.node.Name }

    -
    +
    { this.props.children } @@ -66,12 +66,12 @@ class Client extends Component {
    - ); + ) } } -function mapStateToProps({ node }) { - return { node }; +function mapStateToProps ({ node }) { + return { node } } Client.propTypes = { @@ -79,7 +79,7 @@ Client.propTypes = { params: PropTypes.object.isRequired, node: PropTypes.object.isRequired, location: PropTypes.object.isRequired, - children: PropTypes.object.isRequired, -}; + children: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(Client); +export default connect(mapStateToProps)(Client) diff --git a/frontend/src/containers/clients.js b/frontend/src/containers/clients.js index eb55be94..679ac2b9 100644 --- a/frontend/src/containers/clients.js +++ b/frontend/src/containers/clients.js @@ -1,18 +1,18 @@ -import React, { PropTypes } from 'react'; -import { connect } from 'react-redux'; -import NomadLink from '../components/NomadLink/NomadLink'; -import FormatBoolean from '../components/FormatBoolean/FormatBoolean'; -import NodeStatus from '../components/NodeStatus/NodeStatus'; +import React, { PropTypes } from 'react' +import { connect } from 'react-redux' +import NomadLink from '../components/NomadLink/NomadLink' +import FormatBoolean from '../components/FormatBoolean/FormatBoolean' +import NodeStatus from '../components/NodeStatus/NodeStatus' const Clients = ({ nodes }) => -
    -
    -
    -
    -

    Clients

    +
    +
    +
    +
    +

    Clients

    -
    - +
    +
    @@ -26,7 +26,7 @@ const Clients = ({ nodes }) => { nodes.map(node => - + @@ -39,14 +39,14 @@ const Clients = ({ nodes }) => - ; + -function mapStateToProps({ nodes }) { - return { nodes }; +function mapStateToProps ({ nodes }) { + return { nodes } } Clients.propTypes = { - nodes: PropTypes.array.isRequired, -}; + nodes: PropTypes.array.isRequired +} -export default connect(mapStateToProps)(Clients); +export default connect(mapStateToProps)(Clients) diff --git a/frontend/src/containers/cluster.js b/frontend/src/containers/cluster.js index 1862d0bd..84c20639 100644 --- a/frontend/src/containers/cluster.js +++ b/frontend/src/containers/cluster.js @@ -1,86 +1,86 @@ -import React, { Component, PropTypes } from 'react'; -import { connect } from 'react-redux'; -import Progressbar from '../components/Progressbar/Progressbar'; -import Events from './events'; -import Statistics from './statistics'; +import React, { Component, PropTypes } from 'react' +import { connect } from 'react-redux' +import Progressbar from '../components/Progressbar/Progressbar' +import Events from './events' +import Statistics from './statistics' class Cluster extends Component { - getChartData() { + getChartData () { const stats = { jobStatus: { running: 0, pending: 0, - dead: 0, + dead: 0 }, jobTypes: { service: 0, batch: 0, - system: 0, + system: 0 }, nodeStatus: { ready: 0, initializing: 0, - down: 0, + down: 0 }, memberStatus: { alive: 0, leaving: 0, left: 0, - shutdown: 0, - }, - }; + shutdown: 0 + } + } for (const job of this.props.jobs) { - stats.jobStatus[job.Status] += 1; - stats.jobTypes[job.Type] += 1; + stats.jobStatus[job.Status] += 1 + stats.jobTypes[job.Type] += 1 } for (const node of this.props.nodes) { - stats.nodeStatus[node.Status] += 1; + stats.nodeStatus[node.Status] += 1 } for (const member of this.props.members) { - stats.memberStatus[member.Status] += 1; + stats.memberStatus[member.Status] += 1 } - return stats; + return stats } - render() { - const data = this.getChartData(); + render () { + const data = this.getChartData() return (
    -
    -
    - +
    +
    +
    -
    - +
    +
    -
    - +
    +
    -
    - +
    +
    - ); + ) } } -function mapStateToProps({ jobs, nodes, members }) { - return { jobs, nodes, members }; +function mapStateToProps ({ jobs, nodes, members }) { + return { jobs, nodes, members } } Cluster.propTypes = { jobs: PropTypes.array.isRequired, nodes: PropTypes.array.isRequired, - members: PropTypes.array.isRequired, -}; + members: PropTypes.array.isRequired +} -export default connect(mapStateToProps)(Cluster); +export default connect(mapStateToProps)(Cluster) diff --git a/frontend/src/containers/evaluation.js b/frontend/src/containers/evaluation.js index 9fdede6e..295c91b1 100644 --- a/frontend/src/containers/evaluation.js +++ b/frontend/src/containers/evaluation.js @@ -1,60 +1,60 @@ -import React, { Component, PropTypes } from 'react'; -import { connect } from 'react-redux'; -import Tabs from '../components/Tabs/Tabs'; -import { WATCH_EVAL, UNWATCH_EVAL } from '../sagas/event'; +import React, { Component, PropTypes } from 'react' +import { connect } from 'react-redux' +import Tabs from '../components/Tabs/Tabs' +import { WATCH_EVAL, UNWATCH_EVAL } from '../sagas/event' class Evaluation extends Component { - constructor(props) { - super(props); + constructor (props) { + super(props) this.state = { tabs: [ { name: 'Info', - path: 'info', + path: 'info' }, { name: 'Allocations', - path: 'allocations', + path: 'allocations' }, { name: 'Raw', - path: 'raw', - }, - ], - }; + path: 'raw' + } + ] + } } - componentWillMount() { + componentWillMount () { this.props.dispatch({ type: WATCH_EVAL, - payload: this.props.params.evalId, - }); + payload: this.props.params.evalId + }) } - componentWillUnmount() { + componentWillUnmount () { this.props.dispatch({ type: UNWATCH_EVAL, - payload: this.props.params.evalId, - }); + payload: this.props.params.evalId + }) } - render() { - if (this.props.evaluation == null) return (null); + render () { + if (this.props.evaluation == null) return (null) - const path = this.props.location.pathname; - const tabSlug = path.split('/').pop(); - const basePath = path.substring(0, path.lastIndexOf('/')); + const path = this.props.location.pathname + const tabSlug = path.split('/').pop() + const basePath = path.substring(0, path.lastIndexOf('/')) return ( -
    -
    -
    -
    -

    Evaluation: { this.props.evaluation.ID }

    +
    +
    +
    +
    +

    Evaluation: { this.props.evaluation.ID }

    -
    +
    { this.props.children } @@ -62,12 +62,12 @@ class Evaluation extends Component {
    - ); + ) } } -function mapStateToProps({ evaluation }) { - return { evaluation }; +function mapStateToProps ({ evaluation }) { + return { evaluation } } Evaluation.propTypes = { @@ -75,7 +75,7 @@ Evaluation.propTypes = { params: PropTypes.object.isRequired, evaluation: PropTypes.object.isRequired, location: PropTypes.object.isRequired, - children: PropTypes.object.isRequired, -}; + children: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(Evaluation); +export default connect(mapStateToProps)(Evaluation) diff --git a/frontend/src/containers/evaluations.js b/frontend/src/containers/evaluations.js index 08511d31..2e6d43a5 100644 --- a/frontend/src/containers/evaluations.js +++ b/frontend/src/containers/evaluations.js @@ -1,29 +1,29 @@ -import React, { PropTypes } from 'react'; -import { connect } from 'react-redux'; -import EvaluationList from '../components/EvaluationList/EvaluationList'; +import React, { PropTypes } from 'react' +import { connect } from 'react-redux' +import EvaluationList from '../components/EvaluationList/EvaluationList' const Evaluations = ({ evaluations }) => -
    -
    -
    -
    -

    Evaluations

    +
    +
    +
    +
    +

    Evaluations

    - +
    -
    ; +
    -function mapStateToProps({ evaluations }) { - return { evaluations }; +function mapStateToProps ({ evaluations }) { + return { evaluations } } Evaluations.defaultProps = { - evaluations: {}, -}; + evaluations: {} +} Evaluations.propTypes = { - evaluations: PropTypes.array.isRequired, -}; + evaluations: PropTypes.array.isRequired +} -export default connect(mapStateToProps)(Evaluations); +export default connect(mapStateToProps)(Evaluations) diff --git a/frontend/src/containers/events.js b/frontend/src/containers/events.js index 2754a82e..c05dc128 100644 --- a/frontend/src/containers/events.js +++ b/frontend/src/containers/events.js @@ -1,18 +1,18 @@ -import React, { Component, PropTypes } from 'react'; -import { connect } from 'react-redux'; -import NomadLink from '../components/NomadLink/NomadLink'; -import FormatTime from '../components/FormatTime/FormatTime'; +import React, { Component, PropTypes } from 'react' +import { connect } from 'react-redux' +import NomadLink from '../components/NomadLink/NomadLink' +import FormatTime from '../components/FormatTime/FormatTime' class Events extends Component { - render() { - const taskEvents = []; + render () { + const taskEvents = [] this.props.allocations.forEach((allocation) => { if (allocation.TaskStates != null) { Object.keys(allocation.TaskStates).forEach((task) => { allocation.TaskStates[task].Events.reverse().forEach((event) => { - if (taskEvents.length === 10) return; - const eventID = `${task}.${event.Time}`; + if (taskEvents.length === 10) return + const eventID = `${task}.${event.Time}` taskEvents.push(
    - ); - }); - }); + ) + }) + }) } - }); + }) return ( -
    -
    -
    -
    -

    Task Events

    +
    +
    +
    +
    +

    Task Events

    -
    -
    ID
    { node.Name }
    @@ -32,21 +32,21 @@ class Events extends Component {
    +
    +
    @@ -63,16 +63,16 @@ class Events extends Component { - ); + ) } } -function mapStateToProps({ allocations }) { - return { allocations }; +function mapStateToProps ({ allocations }) { + return { allocations } } Events.propTypes = { - allocations: PropTypes.array.isRequired, -}; + allocations: PropTypes.array.isRequired +} -export default connect(mapStateToProps)(Events); +export default connect(mapStateToProps)(Events) diff --git a/frontend/src/containers/job.js b/frontend/src/containers/job.js index 1b080ddd..2af7162c 100644 --- a/frontend/src/containers/job.js +++ b/frontend/src/containers/job.js @@ -1,72 +1,72 @@ -import React, { Component, PropTypes } from 'react'; -import { connect } from 'react-redux'; -import Tabs from '../components/Tabs/Tabs'; -import { WATCH_JOB, UNWATCH_JOB } from '../sagas/event'; +import React, { Component, PropTypes } from 'react' +import { connect } from 'react-redux' +import Tabs from '../components/Tabs/Tabs' +import { WATCH_JOB, UNWATCH_JOB } from '../sagas/event' class Job extends Component { - constructor(props) { - super(props); + constructor (props) { + super(props) this.state = { tabs: [ { name: 'Info', - path: 'info', + path: 'info' }, { name: 'Allocations', - path: 'allocations', + path: 'allocations' }, { name: 'Evaluations', - path: 'evaluations', + path: 'evaluations' }, { name: 'Tasks Groups', - path: 'taskGroups', + path: 'taskGroups' }, { name: 'Tasks', - path: 'tasks', + path: 'tasks' }, { name: 'Raw', - path: 'raw', - }, - ], - }; + path: 'raw' + } + ] + } } - componentWillMount() { + componentWillMount () { this.props.dispatch({ type: WATCH_JOB, - payload: this.props.params.jobId, - }); + payload: this.props.params.jobId + }) } - componentWillUnmount() { + componentWillUnmount () { this.props.dispatch({ type: UNWATCH_JOB, - payload: this.props.params.jobId, - }); + payload: this.props.params.jobId + }) } - render() { - if (this.props.job == null) return (null); + render () { + if (this.props.job == null) return (null) - const path = this.props.location.pathname; - const tabSlug = path.split('/').pop(); - const basePath = path.substring(0, path.lastIndexOf('/')); + const path = this.props.location.pathname + const tabSlug = path.split('/').pop() + const basePath = path.substring(0, path.lastIndexOf('/')) return ( -
    -
    -
    -
    -

    Job: { this.props.job.ID }

    +
    +
    +
    +
    +

    Job: { this.props.job.ID }

    -
    +
    { this.props.children } @@ -74,12 +74,12 @@ class Job extends Component {
    - ); + ) } } -function mapStateToProps({ job }) { - return { job }; +function mapStateToProps ({ job }) { + return { job } } Job.propTypes = { @@ -87,7 +87,7 @@ Job.propTypes = { params: PropTypes.object.isRequired, job: PropTypes.object.isRequired, location: PropTypes.object.isRequired, - children: PropTypes.object.isRequired, -}; + children: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(Job); +export default connect(mapStateToProps)(Job) diff --git a/frontend/src/containers/jobs.js b/frontend/src/containers/jobs.js index 1c8e9e6a..ff111b84 100644 --- a/frontend/src/containers/jobs.js +++ b/frontend/src/containers/jobs.js @@ -1,26 +1,26 @@ -import React, { Component, PropTypes } from 'react'; -import { connect } from 'react-redux'; -import { Link } from 'react-router'; -import { DropdownButton } from 'react-bootstrap'; -import NomadLink from '../components/NomadLink/NomadLink'; +import React, { Component, PropTypes } from 'react' +import { connect } from 'react-redux' +import { Link } from 'react-router' +import { DropdownButton } from 'react-bootstrap' +import NomadLink from '../components/NomadLink/NomadLink' const jobStatusColors = { running: '', pending: 'warning', - dead: 'danger', -}; + dead: 'danger' +} -const summaryLabels = ['Starting', 'Running', 'Queued', 'Complete', 'Failed', 'Lost']; +const summaryLabels = ['Starting', 'Running', 'Queued', 'Complete', 'Failed', 'Lost'] const getJobStatisticsHeader = () => { - const output = []; + const output = [] summaryLabels.forEach((key) => { - output.push(
    ); - }); + output.push() + }) - return output; -}; + return output +} const getJobStatisticsRow = (job) => { const counter = { @@ -29,117 +29,117 @@ const getJobStatisticsRow = (job) => { Failed: 0, Running: 0, Starting: 0, - Lost: 0, - }; + Lost: 0 + } if (job.JobSummary !== null) { - const summary = job.JobSummary.Summary; + const summary = job.JobSummary.Summary Object.keys(summary).forEach((taskGroupID) => { - counter.Queued += summary[taskGroupID].Queued; - counter.Complete += summary[taskGroupID].Complete; - counter.Failed += summary[taskGroupID].Failed; - counter.Running += summary[taskGroupID].Running; - counter.Starting += summary[taskGroupID].Starting; - counter.Lost += summary[taskGroupID].Lost; - }); + counter.Queued += summary[taskGroupID].Queued + counter.Complete += summary[taskGroupID].Complete + counter.Failed += summary[taskGroupID].Failed + counter.Running += summary[taskGroupID].Running + counter.Starting += summary[taskGroupID].Starting + counter.Lost += summary[taskGroupID].Lost + }) } else { - Object.keys(counter).forEach(key => (counter[key] = 'N/A')); + Object.keys(counter).forEach(key => (counter[key] = 'N/A')) } - const output = []; + const output = [] summaryLabels.forEach((key) => { - output.push(); - }); + output.push() + }) - return output; -}; + return output +} class Jobs extends Component { - filteredJobs() { - const query = this.props.location.query || {}; - let jobs = this.props.jobs; + filteredJobs () { + const query = this.props.location.query || {} + let jobs = this.props.jobs if ('job_type' in query) { - jobs = jobs.filter(job => job.Type === query.job_type); + jobs = jobs.filter(job => job.Type === query.job_type) } if ('job_status' in query) { - jobs = jobs.filter(job => job.Status === query.job_status); + jobs = jobs.filter(job => job.Status === query.job_status) } - return jobs; + return jobs } - jobTypeFilter() { - const location = this.props.location; - const query = this.props.location.query || {}; + jobTypeFilter () { + const location = this.props.location + const query = this.props.location.query || {} - let title = 'Job Type'; + let title = 'Job Type' if ('job_type' in query) { - title = {title}: { query.job_type }; + title = {title}: { query.job_type } } return ( - +
  • - Any -
  • System
  • Batch
  • Service
  • - ); + ) } - jobStatusFilter() { - const location = this.props.location; - const query = this.props.location.query || {}; + jobStatusFilter () { + const location = this.props.location + const query = this.props.location.query || {} - let title = 'Job Status'; + let title = 'Job Status' if ('job_status' in query) { - title = {title}: { query.job_status }; + title = {title}: { query.job_status } } return ( - +
  • - Any -
  • Running
  • Pending
  • Dead
  • - ); + ) } - taskGroupCount(job) { - let taskGroupCount = 'N/A'; + taskGroupCount (job) { + let taskGroupCount = 'N/A' if (job.JobSummary !== null) { - taskGroupCount = Object.keys(job.JobSummary.Summary).length; + taskGroupCount = Object.keys(job.JobSummary.Summary).length } - return taskGroupCount; + return taskGroupCount } - render() { + render () { return ( -
    -
    -
    -
    -

    Jobs

    +
    +
    +
    +
    +

    Jobs

    {this.jobStatusFilter()}   {this.jobTypeFilter()}
    -
    -
    Task { key }{ key }{counter[key]}{counter[key]}
    +
    +
    - - - - + + + + { getJobStatisticsHeader() } @@ -160,22 +160,22 @@ class Jobs extends Component { - ); + ) } } -function mapStateToProps({ jobs }) { - return { jobs }; +function mapStateToProps ({ jobs }) { + return { jobs } } Jobs.defaultProps = { jobs: [], - location: {}, -}; + location: {} +} Jobs.propTypes = { jobs: PropTypes.array.isRequired, - location: PropTypes.object.isRequired, -}; + location: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(Jobs); +export default connect(mapStateToProps)(Jobs) diff --git a/frontend/src/containers/server.js b/frontend/src/containers/server.js index 098d4258..7ebe3c56 100644 --- a/frontend/src/containers/server.js +++ b/frontend/src/containers/server.js @@ -1,56 +1,56 @@ -import React, { Component, PropTypes } from 'react'; -import { connect } from 'react-redux'; -import Tabs from '../components/Tabs/Tabs'; -import { WATCH_MEMBER, UNWATCH_MEMBER } from '../sagas/event'; +import React, { Component, PropTypes } from 'react' +import { connect } from 'react-redux' +import Tabs from '../components/Tabs/Tabs' +import { WATCH_MEMBER, UNWATCH_MEMBER } from '../sagas/event' class Server extends Component { - constructor(props) { - super(props); + constructor (props) { + super(props) this.state = { tabs: [ { name: 'Info', - path: 'info', + path: 'info' }, { name: 'Raw', - path: 'raw', - }, - ], - }; + path: 'raw' + } + ] + } } - componentWillMount() { + componentWillMount () { this.props.dispatch({ type: WATCH_MEMBER, - payload: this.props.params.memberId, - }); + payload: this.props.params.memberId + }) } - componentWillUnmount() { + componentWillUnmount () { this.props.dispatch({ type: UNWATCH_MEMBER, - payload: this.props.params.memberId, - }); + payload: this.props.params.memberId + }) } - render() { - if (this.props.member == null) return (null); + render () { + if (this.props.member == null) return (null) - const path = this.props.location.pathname; - const tabSlug = path.split('/').pop(); - const basePath = path.substring(0, path.lastIndexOf('/')); + const path = this.props.location.pathname + const tabSlug = path.split('/').pop() + const basePath = path.substring(0, path.lastIndexOf('/')) return ( -
    -
    -
    -
    -

    Server: { this.props.member.Name }

    +
    +
    +
    +
    +

    Server: { this.props.member.Name }

    -
    +
    { this.props.children } @@ -58,12 +58,12 @@ class Server extends Component {
    - ); + ) } } -function mapStateToProps({ member }) { - return { member }; +function mapStateToProps ({ member }) { + return { member } } Server.propTypes = { @@ -71,7 +71,7 @@ Server.propTypes = { params: PropTypes.object.isRequired, location: PropTypes.object.isRequired, member: PropTypes.object.isRequired, - children: PropTypes.object.isRequired, -}; + children: PropTypes.object.isRequired +} -export default connect(mapStateToProps)(Server); +export default connect(mapStateToProps)(Server) diff --git a/frontend/src/containers/servers.js b/frontend/src/containers/servers.js index d8e86539..74802da5 100644 --- a/frontend/src/containers/servers.js +++ b/frontend/src/containers/servers.js @@ -1,18 +1,18 @@ -import React, { PropTypes } from 'react'; -import { connect } from 'react-redux'; -import NomadLink from '../components/NomadLink/NomadLink'; -import FormatBoolean from '../components/FormatBoolean/FormatBoolean'; +import React, { PropTypes } from 'react' +import { connect } from 'react-redux' +import NomadLink from '../components/NomadLink/NomadLink' +import FormatBoolean from '../components/FormatBoolean/FormatBoolean' const Servers = ({ members }) => { return ( -
    -
    -
    -
    -

    Servers

    +
    +
    +
    +
    +

    Servers

    -
    -
    IDStatusTypePriorityTask GroupsStatusTypePriorityTask Groups
    +
    +
    @@ -31,7 +31,7 @@ const Servers = ({ members }) => { { members.map((member) => { return ( - + @@ -42,7 +42,7 @@ const Servers = ({ members }) => { - ); + ) }) } @@ -51,15 +51,15 @@ const Servers = ({ members }) => { - ); -}; + ) +} -function mapStateToProps({ members }) { - return { members }; +function mapStateToProps ({ members }) { + return { members } } Servers.propTypes = { - members: PropTypes.array.isRequired, -}; + members: PropTypes.array.isRequired +} -export default connect(mapStateToProps)(Servers); +export default connect(mapStateToProps)(Servers) diff --git a/frontend/src/containers/statistics.js b/frontend/src/containers/statistics.js index 261a78a9..e2ca8449 100644 --- a/frontend/src/containers/statistics.js +++ b/frontend/src/containers/statistics.js @@ -1,53 +1,53 @@ -import React, { PropTypes } from 'react'; -import { connect } from 'react-redux'; -import Progressbar from '../components/Progressbar/Progressbar'; +import React, { PropTypes } from 'react' +import { connect } from 'react-redux' +import Progressbar from '../components/Progressbar/Progressbar' const Statistics = ({ jobs }) => { const clientStatus = { Running: 0, - Starting: 0, - }; + Starting: 0 + } - let hasJobSummary = true; + let hasJobSummary = true Object.values(jobs).forEach((job) => { // Guard against releases < 0.4.1 which don't have job summaries if (job.JobSummary === null) { - hasJobSummary = false; - return; + hasJobSummary = false + return } Object.keys(job.JobSummary.Summary).forEach((taskGroup) => { Object.keys(job.JobSummary.Summary[taskGroup]).forEach((stat) => { if (!(stat in clientStatus)) { - clientStatus[stat] = 0; + clientStatus[stat] = 0 } - clientStatus[stat] += job.JobSummary.Summary[taskGroup][stat]; - }); - }); - }); + clientStatus[stat] += job.JobSummary.Summary[taskGroup][stat] + }) + }) + }) if (!hasJobSummary) { - return
    ; + return
    } - delete clientStatus.Complete; + delete clientStatus.Complete return ( -
    -
    - +
    +
    +
    - ); -}; + ) +} -function mapStateToProps({ jobs }) { - return { jobs }; +function mapStateToProps ({ jobs }) { + return { jobs } } Statistics.propTypes = { - jobs: PropTypes.array.isRequired, -}; + jobs: PropTypes.array.isRequired +} -export default connect(mapStateToProps)(Statistics); +export default connect(mapStateToProps)(Statistics) diff --git a/frontend/src/helpers/time.js b/frontend/src/helpers/time.js index 760b09cf..df31c9be 100644 --- a/frontend/src/helpers/time.js +++ b/frontend/src/helpers/time.js @@ -1,21 +1,21 @@ -import moment from 'moment'; +import moment from 'moment' -const nanosecondLength = 19; +const nanosecondLength = 19 -function normalizeTime(time) { - const length = time.toString().length; +function normalizeTime (time) { + const length = time.toString().length if (length >= nanosecondLength) { - return time / 1000000; + return time / 1000000 } - return time; + return time } -export default function getMoment(time) { +export default function getMoment (time) { if (time === 'now' || time === null) { - return moment(); + return moment() } - return moment(normalizeTime(time), 'x'); + return moment(normalizeTime(time), 'x') } diff --git a/frontend/src/helpers/uuid.js b/frontend/src/helpers/uuid.js index 70957333..893602e9 100644 --- a/frontend/src/helpers/uuid.js +++ b/frontend/src/helpers/uuid.js @@ -1,5 +1,5 @@ -function shortUUID(ID) { - return ID.substring(0, 8); +function shortUUID (ID) { + return ID.substring(0, 8) } -export default shortUUID; +export default shortUUID diff --git a/frontend/src/main.js b/frontend/src/main.js index f5bde2c9..3798982a 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -1,14 +1,14 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import { browserHistory } from 'react-router'; -import { Provider } from 'react-redux'; +import React from 'react' +import ReactDOM from 'react-dom' +import { browserHistory } from 'react-router' +import { Provider } from 'react-redux' // import Perf from 'react-addons-perf'; // import 'bootstrap/dist/css/bootstrap.min.css'; -import '../assets/nomad-ui.css'; +import '../assets/nomad-ui.css' -import AppRouter from './router'; -import configureStore from './store'; +import AppRouter from './router' +import configureStore from './store' // Perf.start(); @@ -18,9 +18,9 @@ configureStore().then((store) => { , document.getElementById('app') - ); + ) }).catch((err) => { - console.log(err); -}); + console.log(err) +}) // window.Perf = Perf; diff --git a/frontend/src/reducers/allocation.js b/frontend/src/reducers/allocation.js index f483d099..9939cc51 100644 --- a/frontend/src/reducers/allocation.js +++ b/frontend/src/reducers/allocation.js @@ -1,29 +1,29 @@ -import { FETCHED_ALLOCS, FETCHED_ALLOC } from '../sagas/event'; +import { FETCHED_ALLOCS, FETCHED_ALLOC } from '../sagas/event' -export function AllocInfoReducer(state = {}, action) { +export function AllocInfoReducer (state = {}, action) { switch (action.type) { case FETCHED_ALLOC: { - const allocation = action.payload; - allocation.TaskGroupId = `${allocation.JobID}.${allocation.TaskGroup}`; - return allocation; + const allocation = action.payload + allocation.TaskGroupId = `${allocation.JobID}.${allocation.TaskGroup}` + return allocation } default: } - return state; + return state } -export function AllocListReducer(state = [], action) { +export function AllocListReducer (state = [], action) { switch (action.type) { case FETCHED_ALLOCS: { const allocations = action.payload.map(allocation => Object.assign({}, allocation, { TaskGroupId: `${allocation.JobID}.${allocation.TaskGroup}` }) - ); + ) - return allocations; + return allocations } default: } - return state; + return state } diff --git a/frontend/src/reducers/evaluation.js b/frontend/src/reducers/evaluation.js index f3ab2347..957e29fe 100644 --- a/frontend/src/reducers/evaluation.js +++ b/frontend/src/reducers/evaluation.js @@ -1,19 +1,19 @@ -import { FETCHED_EVALS, FETCHED_EVAL } from '../sagas/event'; +import { FETCHED_EVALS, FETCHED_EVAL } from '../sagas/event' -export function EvalInfoReducer(state = {}, action) { +export function EvalInfoReducer (state = {}, action) { switch (action.type) { case FETCHED_EVAL: - return action.payload; + return action.payload default: } - return state; + return state } -export function EvalListReducer(state = [], action) { +export function EvalListReducer (state = [], action) { switch (action.type) { case FETCHED_EVALS: - return action.payload; + return action.payload default: } - return state; + return state } diff --git a/frontend/src/reducers/filesystem.js b/frontend/src/reducers/filesystem.js index f2d88476..5f1e0756 100644 --- a/frontend/src/reducers/filesystem.js +++ b/frontend/src/reducers/filesystem.js @@ -1,23 +1,23 @@ -import { FETCHED_DIR, FETCHED_FILE, CLEAR_FILE_PATH, CLEAR_RECEIVED_FILE_DATA } from '../sagas/event'; +import { FETCHED_DIR, FETCHED_FILE, CLEAR_FILE_PATH, CLEAR_RECEIVED_FILE_DATA } from '../sagas/event' -export function DirectoryReducer(state = [], action) { +export function DirectoryReducer (state = [], action) { switch (action.type) { case FETCHED_DIR: - return action.payload; + return action.payload default: } - return state; + return state } -export function FileReducer(state = { File: '' }, action) { +export function FileReducer (state = { File: '' }, action) { switch (action.type) { case CLEAR_FILE_PATH: - return Object.assign({}, state, { File: '', Data: '' }); + return Object.assign({}, state, { File: '', Data: '' }) case CLEAR_RECEIVED_FILE_DATA: - return Object.assign({}, state, { Data: '' }); + return Object.assign({}, state, { Data: '' }) case FETCHED_FILE: - return action.payload; + return action.payload default: } - return state; + return state } diff --git a/frontend/src/reducers/job.js b/frontend/src/reducers/job.js index 9e605fb1..57ade3a4 100644 --- a/frontend/src/reducers/job.js +++ b/frontend/src/reducers/job.js @@ -1,30 +1,30 @@ -import { FETCHED_JOB, FETCHED_JOBS } from '../sagas/event'; +import { FETCHED_JOB, FETCHED_JOBS } from '../sagas/event' -export function JobInfoReducer(state = { TaskGroups: [] }, action) { +export function JobInfoReducer (state = { TaskGroups: [] }, action) { switch (action.type) { case FETCHED_JOB: { - const job = action.payload; + const job = action.payload job.TaskGroups.forEach((group, gidx) => { - job.TaskGroups[gidx].ID = `${job.ID}.${group.Name}`; - }); + job.TaskGroups[gidx].ID = `${job.ID}.${group.Name}` + }) job.TaskGroups.forEach((group, gidx) => { group.Tasks.forEach((task, tidx) => { - job.TaskGroups[gidx].Tasks[tidx].ID = `${group.ID}.${task.Name}`; - }); - }); - return job; + job.TaskGroups[gidx].Tasks[tidx].ID = `${group.ID}.${task.Name}` + }) + }) + return job } default: } - return state; + return state } -export function JobListReducer(state = [], action) { +export function JobListReducer (state = [], action) { switch (action.type) { case FETCHED_JOBS: - return action.payload; + return action.payload default: } - return state; + return state } diff --git a/frontend/src/reducers/member.js b/frontend/src/reducers/member.js index a7782a39..ca4aab71 100644 --- a/frontend/src/reducers/member.js +++ b/frontend/src/reducers/member.js @@ -1,19 +1,19 @@ -import { FETCHED_MEMBERS, FETCHED_MEMBER } from '../sagas/event'; +import { FETCHED_MEMBERS, FETCHED_MEMBER } from '../sagas/event' -export function MemberInfoReducer(state = { Tags: {} }, action) { +export function MemberInfoReducer (state = { Tags: {} }, action) { switch (action.type) { case FETCHED_MEMBER: - return action.payload; + return action.payload default: } - return state; + return state } -export function MemberListReducer(state = [], action) { +export function MemberListReducer (state = [], action) { switch (action.type) { case FETCHED_MEMBERS: - return action.payload; + return action.payload default: } - return state; + return state } diff --git a/frontend/src/reducers/node.js b/frontend/src/reducers/node.js index 24ff9cb5..c89b7546 100644 --- a/frontend/src/reducers/node.js +++ b/frontend/src/reducers/node.js @@ -1,19 +1,19 @@ -import { FETCHED_NODES, FETCHED_NODE } from '../sagas/event'; +import { FETCHED_NODES, FETCHED_NODE } from '../sagas/event' -export function NodeInfoReducer(state = {}, action) { +export function NodeInfoReducer (state = {}, action) { switch (action.type) { case FETCHED_NODE: - return action.payload; + return action.payload default: } - return state; + return state } -export function NodeListReducer(state = [], action) { +export function NodeListReducer (state = [], action) { switch (action.type) { case FETCHED_NODES: - return action.payload; + return action.payload default: } - return state; + return state } diff --git a/frontend/src/reducers/root.js b/frontend/src/reducers/root.js index 2926074b..494b070f 100644 --- a/frontend/src/reducers/root.js +++ b/frontend/src/reducers/root.js @@ -1,11 +1,11 @@ -import { combineReducers } from 'redux'; +import { combineReducers } from 'redux' -import { MemberInfoReducer, MemberListReducer } from './member'; -import { JobInfoReducer, JobListReducer } from './job'; -import { AllocInfoReducer, AllocListReducer } from './allocation'; -import { EvalInfoReducer, EvalListReducer } from './evaluation'; -import { NodeInfoReducer, NodeListReducer } from './node'; -import { DirectoryReducer, FileReducer } from './filesystem'; +import { MemberInfoReducer, MemberListReducer } from './member' +import { JobInfoReducer, JobListReducer } from './job' +import { AllocInfoReducer, AllocListReducer } from './allocation' +import { EvalInfoReducer, EvalListReducer } from './evaluation' +import { NodeInfoReducer, NodeListReducer } from './node' +import { DirectoryReducer, FileReducer } from './filesystem' const rootReducer = combineReducers({ member: MemberInfoReducer, @@ -19,7 +19,7 @@ const rootReducer = combineReducers({ evaluation: EvalInfoReducer, evaluations: EvalListReducer, directory: DirectoryReducer, - file: FileReducer, -}); + file: FileReducer +}) -export default rootReducer; +export default rootReducer diff --git a/frontend/src/router.js b/frontend/src/router.js index 238b9544..5dfd338d 100644 --- a/frontend/src/router.js +++ b/frontend/src/router.js @@ -1,100 +1,100 @@ -import React, { PropTypes } from 'react'; -import { Router, Route, Redirect, IndexRedirect, browserHistory } from 'react-router'; +import React, { PropTypes } from 'react' +import { Router, Route, Redirect, IndexRedirect, browserHistory } from 'react-router' -import App from './components/app'; -import Cluster from './containers/cluster'; +import App from './components/app' +import Cluster from './containers/cluster' -import Jobs from './containers/jobs'; -import Job from './containers/job'; -import JobInfo from './components/JobInfo/JobInfo'; -import JobAllocs from './components/JobAllocations/JobAllocations'; -import JobEvals from './components/JobEvaluations/JobEvaluations'; -import JobTasks from './components/JobTasks/JobTasks'; -import JobTaskGroups from './components/JobTaskGroups/JobTaskGroups'; -import JobRaw from './components/JobRaw/JobRaw'; +import Jobs from './containers/jobs' +import Job from './containers/job' +import JobInfo from './components/JobInfo/JobInfo' +import JobAllocs from './components/JobAllocations/JobAllocations' +import JobEvals from './components/JobEvaluations/JobEvaluations' +import JobTasks from './components/JobTasks/JobTasks' +import JobTaskGroups from './components/JobTaskGroups/JobTaskGroups' +import JobRaw from './components/JobRaw/JobRaw' -import Allocations from './containers/allocations'; -import Allocation from './containers/allocation'; -import AllocInfo from './components/AllocationInfo/AllocationInfo'; -import AllocFiles from './components/AllocationFiles/AllocationFiles'; -import AllocRaw from './components/AllocationRaw/AllocationRaw'; +import Allocations from './containers/allocations' +import Allocation from './containers/allocation' +import AllocInfo from './components/AllocationInfo/AllocationInfo' +import AllocFiles from './components/AllocationFiles/AllocationFiles' +import AllocRaw from './components/AllocationRaw/AllocationRaw' -import Evaluations from './containers/evaluations'; -import Evaluation from './containers/evaluation'; -import EvalInfo from './components/EvaluationInfo/EvaluationInfo'; -import EvalAllocations from './components/EvaluationAllocations/EvaluationAllocations'; -import EvalRaw from './components/EvaluationRaw/EvaluationRaw'; +import Evaluations from './containers/evaluations' +import Evaluation from './containers/evaluation' +import EvalInfo from './components/EvaluationInfo/EvaluationInfo' +import EvalAllocations from './components/EvaluationAllocations/EvaluationAllocations' +import EvalRaw from './components/EvaluationRaw/EvaluationRaw' -import Clients from './containers/clients'; -import Client from './containers/client'; -import ClientInfo from './components/ClientInfo/ClientInfo'; -import ClientAllocations from './components/ClientAllocations/ClientAllocations'; -import ClientEvaluations from './components/ClientEvaluations/ClientEvaluations'; -import ClientRaw from './components/ClientRaw/ClientRaw'; +import Clients from './containers/clients' +import Client from './containers/client' +import ClientInfo from './components/ClientInfo/ClientInfo' +import ClientAllocations from './components/ClientAllocations/ClientAllocations' +import ClientEvaluations from './components/ClientEvaluations/ClientEvaluations' +import ClientRaw from './components/ClientRaw/ClientRaw' -import Servers from './containers/servers'; -import Server from './containers/server'; -import ServerInfo from './components/ServerInfo/ServerInfo'; -import ServerRaw from './components/ServerRaw/ServerRaw'; +import Servers from './containers/servers' +import Server from './containers/server' +import ServerInfo from './components/ServerInfo/ServerInfo' +import ServerRaw from './components/ServerRaw/ServerRaw' const AppRouter = ({ history }) => - - - + + + - - - - - + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - + + + + + + + - - - - + + + + - - + + - - - - - - + + + + + + - ; + AppRouter.propTypes = { - history: PropTypes.instanceOf(browserHistory.constructor).isRequired, -}; + history: PropTypes.instanceOf(browserHistory.constructor).isRequired +} -export default AppRouter; +export default AppRouter diff --git a/frontend/src/sagas/event.js b/frontend/src/sagas/event.js index ea75a666..041ec25e 100644 --- a/frontend/src/sagas/event.js +++ b/frontend/src/sagas/event.js @@ -1,66 +1,66 @@ -import { delay, eventChannel } from 'redux-saga'; -import { fork, take, call, put } from 'redux-saga/effects'; - -export const FETCHED_JOBS = 'FETCHED_JOBS'; -export const FETCHED_JOB = 'FETCHED_JOB'; -export const WATCH_JOB = 'WATCH_JOB'; -export const UNWATCH_JOB = 'UNWATCH_JOB'; - -export const FETCHED_MEMBERS = 'FETCHED_MEMBERS'; -export const FETCHED_MEMBER = 'FETCHED_MEMBER'; -export const FETCH_MEMBER = 'FETCH_MEMBER'; -export const WATCH_MEMBER = 'WATCH_MEMBER'; -export const UNWATCH_MEMBER = 'UNWATCH_MEMBER'; - -export const FETCHED_NODES = 'FETCHED_NODES'; -export const FETCHED_NODE = 'FETCHED_NODE'; -export const FETCH_NODE = 'FETCH_NODE'; -export const WATCH_NODE = 'WATCH_NODE'; -export const UNWATCH_NODE = 'UNWATCH_NODE'; - -export const FETCHED_EVALS = 'FETCHED_EVALS'; -export const FETCHED_EVAL = 'FETCHED_EVAL'; -export const WATCH_EVAL = 'WATCH_EVAL'; -export const UNWATCH_EVAL = 'UNWATCH_EVAL'; - -export const FETCHED_ALLOCS = 'FETCHED_ALLOCS'; -export const FETCHED_ALLOC = 'FETCHED_ALLOC'; -export const WATCH_ALLOC = 'WATCH_ALLOC'; -export const UNWATCH_ALLOC = 'UNWATCH_ALLOC'; - -export const FETCH_DIR = 'FETCH_DIR'; -export const FETCHED_DIR = 'FETCHED_DIR'; - -export const WATCH_FILE = 'WATCH_FILE'; -export const UNWATCH_FILE = 'UNWATCH_FILE'; -export const FETCHED_FILE = 'FETCHED_FILE'; - -export const CLEAR_FILE_PATH = 'CLEAR_FILE_PATH'; -export const CLEAR_RECEIVED_FILE_DATA = 'CLEAR_RECEIVED_FILE_DATA'; - -function subscribe(socket) { +import { delay, eventChannel } from 'redux-saga' +import { fork, take, call, put } from 'redux-saga/effects' + +export const FETCHED_JOBS = 'FETCHED_JOBS' +export const FETCHED_JOB = 'FETCHED_JOB' +export const WATCH_JOB = 'WATCH_JOB' +export const UNWATCH_JOB = 'UNWATCH_JOB' + +export const FETCHED_MEMBERS = 'FETCHED_MEMBERS' +export const FETCHED_MEMBER = 'FETCHED_MEMBER' +export const FETCH_MEMBER = 'FETCH_MEMBER' +export const WATCH_MEMBER = 'WATCH_MEMBER' +export const UNWATCH_MEMBER = 'UNWATCH_MEMBER' + +export const FETCHED_NODES = 'FETCHED_NODES' +export const FETCHED_NODE = 'FETCHED_NODE' +export const FETCH_NODE = 'FETCH_NODE' +export const WATCH_NODE = 'WATCH_NODE' +export const UNWATCH_NODE = 'UNWATCH_NODE' + +export const FETCHED_EVALS = 'FETCHED_EVALS' +export const FETCHED_EVAL = 'FETCHED_EVAL' +export const WATCH_EVAL = 'WATCH_EVAL' +export const UNWATCH_EVAL = 'UNWATCH_EVAL' + +export const FETCHED_ALLOCS = 'FETCHED_ALLOCS' +export const FETCHED_ALLOC = 'FETCHED_ALLOC' +export const WATCH_ALLOC = 'WATCH_ALLOC' +export const UNWATCH_ALLOC = 'UNWATCH_ALLOC' + +export const FETCH_DIR = 'FETCH_DIR' +export const FETCHED_DIR = 'FETCHED_DIR' + +export const WATCH_FILE = 'WATCH_FILE' +export const UNWATCH_FILE = 'UNWATCH_FILE' +export const FETCHED_FILE = 'FETCHED_FILE' + +export const CLEAR_FILE_PATH = 'CLEAR_FILE_PATH' +export const CLEAR_RECEIVED_FILE_DATA = 'CLEAR_RECEIVED_FILE_DATA' + +function subscribe (socket) { return eventChannel((emit) => { // eslint-disable-next-line no-param-reassign socket.onmessage = (event) => { - const data = JSON.parse(event.data); + const data = JSON.parse(event.data) emit({ type: data.Type, - payload: data.Payload, - }); - }; - return () => {}; - }); + payload: data.Payload + }) + } + return () => {} + }) } -function* read(socket) { - const channel = yield call(subscribe, socket); +function* read (socket) { + const channel = yield call(subscribe, socket) while (true) { - const action = yield take(channel); - yield put(action); + const action = yield take(channel) + yield put(action) } } -function* write(socket) { +function* write (socket) { while (true) { const action = yield take([ WATCH_JOB, @@ -77,62 +77,62 @@ function* write(socket) { FETCH_MEMBER, FETCH_DIR, WATCH_FILE, - UNWATCH_FILE, - ]); - socket.send(JSON.stringify(action)); + UNWATCH_FILE + ]) + socket.send(JSON.stringify(action)) } } -function* transport(socket) { - yield fork(read, socket); - yield fork(write, socket); +function* transport (socket) { + yield fork(read, socket) + yield fork(write, socket) } -function connectTo(url) { - const socket = new WebSocket(url); +function connectTo (url) { + const socket = new WebSocket(url) const resolver = (resolve, reject) => { const timeout = setTimeout(() => { - reject('Unable to connect to the backend...'); - }, 2000); + reject('Unable to connect to the backend...') + }, 2000) socket.onopen = () => { - resolve(socket); - clearTimeout(timeout); - }; - }; + resolve(socket) + clearTimeout(timeout) + } + } - return new Promise(resolver.bind(socket)); + return new Promise(resolver.bind(socket)) } -function* events(socket) { +function* events (socket) { while (true) { - yield call(transport, socket); - yield delay(5000); + yield call(transport, socket) + yield delay(5000) } } -export default function eventSaga() { +export default function eventSaga () { return new Promise((resolve, reject) => { - const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'; + const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:' // If we build production page, assume /ws run inside the go-binary // and such on same host+port otherwise assume development, where we // re-use the hostname but use GO_PORT end with fallback to :3000. - let hostname; + let hostname if (process.env.NODE_ENV === 'production') { - hostname = location.host; + hostname = location.host } else { - hostname = `${location.hostname}:${process.env.GO_PORT}` || 3000; + hostname = `${location.hostname}:${process.env.GO_PORT}` || 3000 } - const url = `${protocol}//${hostname}/ws`; - const p = connectTo(url); + const url = `${protocol}//${hostname}/ws` + const p = connectTo(url) return p.then((socket) => { - resolve(function* eventGenerator() { yield fork(events, socket); }); + resolve(function* eventGenerator () { yield fork(events, socket) }) }).catch((err) => { - reject(err); - }); - }); + reject(err) + }) + }) } diff --git a/frontend/src/store.js b/frontend/src/store.js index d91c6c99..d651aaaa 100644 --- a/frontend/src/store.js +++ b/frontend/src/store.js @@ -1,10 +1,10 @@ -import { createStore, applyMiddleware, compose } from 'redux'; -import createSagaMiddleware, { END } from 'redux-saga'; -import rootReducer from './reducers/root'; -import eventSaga from './sagas/event'; +import { createStore, applyMiddleware, compose } from 'redux' +import createSagaMiddleware, { END } from 'redux-saga' +import rootReducer from './reducers/root' +import eventSaga from './sagas/event' -export default function configureStore(initialState) { - const sagaMiddleware = createSagaMiddleware(); +export default function configureStore (initialState) { + const sagaMiddleware = createSagaMiddleware() const store = createStore( rootReducer, @@ -19,27 +19,27 @@ export default function configureStore(initialState) { typeof window === 'object' && typeof window.devToolsExtension !== 'undefined' ? window.devToolsExtension() : f => f ) - ); + ) if (module.hot) { // Enable Webpack hot module replacement for reducers module.hot.accept('./reducers/root', () => { // eslint-disable-next-line global-require - const nextRootReducer = require('./reducers/root').default; + const nextRootReducer = require('./reducers/root').default - store.replaceReducer(nextRootReducer); - }); + store.replaceReducer(nextRootReducer) + }) } - store.runSaga = sagaMiddleware.run; - store.close = () => store.dispatch(END); + store.runSaga = sagaMiddleware.run + store.close = () => store.dispatch(END) return new Promise((resolve, reject) => { eventSaga().then((gen) => { - sagaMiddleware.run(gen); - resolve(store); + sagaMiddleware.run(gen) + resolve(store) }).catch((err) => { - reject(err); - }); - }); + reject(err) + }) + }) } diff --git a/frontend/webpack-base.config.js b/frontend/webpack-base.config.js index 614f3816..1718ce22 100644 --- a/frontend/webpack-base.config.js +++ b/frontend/webpack-base.config.js @@ -17,7 +17,11 @@ module.exports = { } ], loaders: [ - + { + test: /\.css$/, + loader: 'style!css?modules', + include: /flexboxgrid/ + } ] }, eslint: { diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js index 0a253a32..49aa1180 100644 --- a/frontend/webpack.config.js +++ b/frontend/webpack.config.js @@ -41,7 +41,8 @@ webpackConfig = merge(webpackConfig, { loaders: [ { test: /\.css$/, - loader: 'style!css!postcss' + loader: 'style!css!postcss', + exclude: /flexboxgrid/ }, { test: /\.jsx?$/, diff --git a/frontend/yarn.lock b/frontend/yarn.lock new file mode 100644 index 00000000..7b43dd7c --- /dev/null +++ b/frontend/yarn.lock @@ -0,0 +1,4875 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +Base64@~0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/Base64/-/Base64-0.2.1.tgz#ba3a4230708e186705065e66babdd4c35cf60028" + +abbrev@1: + version "1.0.9" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + +accepts@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" + dependencies: + mime-types "~2.1.11" + negotiator "0.6.1" + +acorn-jsx@^3.0.0, acorn-jsx@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + dependencies: + acorn "^3.0.4" + +acorn@^3.0.0, acorn@^3.0.4: + version "3.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + +acorn@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.3.tgz#1a3e850b428e73ba6b09d1cc527f5aaad4d03ef1" + +ajv-keywords@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.2.0.tgz#676c4f087bfe1e8b12dca6fda2f3c74f417b099c" + +ajv@^4.7.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.9.1.tgz#08e1b0a5fddc8b844d28ca7b03510e78812ee3a0" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + +alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + +ansi-escapes@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + +ansi-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.0.0.tgz#c5061b6e0ef8a81775e50f5d66151bf6bf371107" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +anymatch@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" + dependencies: + arrify "^1.0.0" + micromatch "^2.1.5" + +aproba@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" + +are-we-there-yet@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.0 || ^1.1.13" + +argparse@^1.0.7: + version "1.0.9" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" + +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + +array-index@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-index/-/array-index-1.0.0.tgz#ec56a749ee103e4e08c790b9c353df16055b97f9" + dependencies: + debug "^2.2.0" + es6-symbol "^3.0.2" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +asap@~2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert@^1.1.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + dependencies: + util "0.10.3" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async-foreach@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" + +async@^0.9.0: + version "0.9.2" + resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + +async@^1.3.0, async@^1.5.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + +async@^2.0.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/async/-/async-2.1.4.tgz#2d2160c7788032e4dd6cbe2502f1f9a2c8f6cde4" + dependencies: + lodash "^4.14.0" + +async@~0.2.6: + version "0.2.10" + resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +autoprefixer@^6.3.1, autoprefixer@^6.3.7: + version "6.5.3" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.5.3.tgz#2d853af66d04449fcf50db3066279ab54c3e4b01" + dependencies: + browserslist "~1.4.0" + caniuse-db "^1.0.30000578" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^5.2.5" + postcss-value-parser "^3.2.3" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws4@^1.2.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755" + +babel-code-frame@^6.11.0, babel-code-frame@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.16.0.tgz#f90e60da0862909d3ce098733b5d3987c97cb8de" + dependencies: + chalk "^1.1.0" + esutils "^2.0.2" + js-tokens "^2.0.0" + +babel-core@^6.18.0, babel-core@^6.18.2: + version "6.18.2" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.18.2.tgz#d8bb14dd6986fa4f3566a26ceda3964fa0e04e5b" + dependencies: + babel-code-frame "^6.16.0" + babel-generator "^6.18.0" + babel-helpers "^6.16.0" + babel-messages "^6.8.0" + babel-register "^6.18.0" + babel-runtime "^6.9.1" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + babylon "^6.11.0" + convert-source-map "^1.1.0" + debug "^2.1.1" + json5 "^0.5.0" + lodash "^4.2.0" + minimatch "^3.0.2" + path-is-absolute "^1.0.0" + private "^0.1.6" + slash "^1.0.0" + source-map "^0.5.0" + +babel-eslint@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.1.1.tgz#8a6a884f085aa7060af69cfc77341c2f99370fb2" + dependencies: + babel-code-frame "^6.16.0" + babel-traverse "^6.15.0" + babel-types "^6.15.0" + babylon "^6.13.0" + lodash.pickby "^4.6.0" + +babel-generator@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.19.0.tgz#9b2f244204777a3d6810ec127c673c87b349fac5" + dependencies: + babel-messages "^6.8.0" + babel-runtime "^6.9.0" + babel-types "^6.19.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.2.0" + source-map "^0.5.0" + +babel-helper-builder-binary-assignment-operator-visitor@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.18.0.tgz#8ae814989f7a53682152e3401a04fabd0bb333a6" + dependencies: + babel-helper-explode-assignable-expression "^6.18.0" + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-helper-builder-react-jsx@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.18.0.tgz#ab02f19a2eb7ace936dd87fa55896d02be59bf71" + dependencies: + babel-runtime "^6.9.0" + babel-types "^6.18.0" + esutils "^2.0.0" + lodash "^4.2.0" + +babel-helper-call-delegate@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.18.0.tgz#05b14aafa430884b034097ef29e9f067ea4133bd" + dependencies: + babel-helper-hoist-variables "^6.18.0" + babel-runtime "^6.0.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-define-map@^6.18.0, babel-helper-define-map@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.18.0.tgz#8d6c85dc7fbb4c19be3de40474d18e97c3676ec2" + dependencies: + babel-helper-function-name "^6.18.0" + babel-runtime "^6.9.0" + babel-types "^6.18.0" + lodash "^4.2.0" + +babel-helper-explode-assignable-expression@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.18.0.tgz#14b8e8c2d03ad735d4b20f1840b24cd1f65239fe" + dependencies: + babel-runtime "^6.0.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-function-name@^6.18.0, babel-helper-function-name@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.18.0.tgz#68ec71aeba1f3e28b2a6f0730190b754a9bf30e6" + dependencies: + babel-helper-get-function-arity "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helper-get-function-arity@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.18.0.tgz#a5b19695fd3f9cdfc328398b47dafcd7094f9f24" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-helper-hoist-variables@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.18.0.tgz#a835b5ab8b46d6de9babefae4d98ea41e866b82a" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-helper-is-react-class@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/babel-helper-is-react-class/-/babel-helper-is-react-class-1.0.0.tgz#ef6f3678b05c76dbdeedadead7af98c2724d8431" + +babel-helper-optimise-call-expression@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.18.0.tgz#9261d0299ee1a4f08a6dd28b7b7c777348fd8f0f" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-helper-regex@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.18.0.tgz#ae0ebfd77de86cb2f1af258e2cc20b5fe893ecc6" + dependencies: + babel-runtime "^6.9.0" + babel-types "^6.18.0" + lodash "^4.2.0" + +babel-helper-replace-supers@^6.18.0, babel-helper-replace-supers@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.18.0.tgz#28ec69877be4144dbd64f4cc3a337e89f29a924e" + dependencies: + babel-helper-optimise-call-expression "^6.18.0" + babel-messages "^6.8.0" + babel-runtime "^6.0.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-helpers@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.16.0.tgz#1095ec10d99279460553e67eb3eee9973d3867e3" + dependencies: + babel-runtime "^6.0.0" + babel-template "^6.16.0" + +babel-loader@^6.2.8: + version "6.2.8" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.2.8.tgz#30d7183aef60afc140b36443676b7acb4c12ac9c" + dependencies: + find-cache-dir "^0.1.1" + loader-utils "^0.2.11" + mkdirp "^0.5.1" + object-assign "^4.0.1" + +babel-messages@^6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.8.0.tgz#bf504736ca967e6d65ef0adb5a2a5f947c8e0eb9" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-check-es2015-constants@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.8.0.tgz#dbf024c32ed37bfda8dee1e76da02386a8d26fe7" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-syntax-class-properties@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + +babel-plugin-syntax-flow@^6.18.0, babel-plugin-syntax-flow@^6.3.13: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" + +babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" + +babel-plugin-syntax-object-rest-spread@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + +babel-plugin-syntax-trailing-function-commas@^6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.13.0.tgz#2b84b7d53dd744f94ff1fad7669406274b23f541" + +babel-plugin-transform-class-properties@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.19.0.tgz#1274b349abaadc835164e2004f4a2444a2788d5f" + dependencies: + babel-helper-function-name "^6.18.0" + babel-plugin-syntax-class-properties "^6.8.0" + babel-runtime "^6.9.1" + babel-template "^6.15.0" + +babel-plugin-transform-es2015-arrow-functions@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.8.0.tgz#5b63afc3181bdc9a8c4d481b5a4f3f7d7fef3d9d" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.8.0.tgz#ed95d629c4b5a71ae29682b998f70d9833eb366d" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-block-scoping@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.18.0.tgz#3bfdcfec318d46df22525cdea88f1978813653af" + dependencies: + babel-runtime "^6.9.0" + babel-template "^6.15.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + lodash "^4.2.0" + +babel-plugin-transform-es2015-classes@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.18.0.tgz#ffe7a17321bf83e494dcda0ae3fc72df48ffd1d9" + dependencies: + babel-helper-define-map "^6.18.0" + babel-helper-function-name "^6.18.0" + babel-helper-optimise-call-expression "^6.18.0" + babel-helper-replace-supers "^6.18.0" + babel-messages "^6.8.0" + babel-runtime "^6.9.0" + babel-template "^6.14.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-plugin-transform-es2015-computed-properties@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.8.0.tgz#f51010fd61b3bd7b6b60a5fdfd307bb7a5279870" + dependencies: + babel-helper-define-map "^6.8.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + +babel-plugin-transform-es2015-destructuring@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.19.0.tgz#ff1d911c4b3f4cab621bd66702a869acd1900533" + dependencies: + babel-runtime "^6.9.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.6.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.8.0.tgz#fd8f7f7171fc108cc1c70c3164b9f15a81c25f7d" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.8.0" + +babel-plugin-transform-es2015-for-of@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.18.0.tgz#4c517504db64bf8cfc119a6b8f177211f2028a70" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-function-name@^6.9.0: + version "6.9.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.9.0.tgz#8c135b17dbd064e5bba56ec511baaee2fca82719" + dependencies: + babel-helper-function-name "^6.8.0" + babel-runtime "^6.9.0" + babel-types "^6.9.0" + +babel-plugin-transform-es2015-literals@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.8.0.tgz#50aa2e5c7958fc2ab25d74ec117e0cc98f046468" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-modules-amd@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.18.0.tgz#49a054cbb762bdf9ae2d8a807076cfade6141e40" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + +babel-plugin-transform-es2015-modules-commonjs@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.18.0.tgz#c15ae5bb11b32a0abdcc98a5837baa4ee8d67bcc" + dependencies: + babel-plugin-transform-strict-mode "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.16.0" + babel-types "^6.18.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.19.0.tgz#50438136eba74527efa00a5b0fefaf1dc4071da6" + dependencies: + babel-helper-hoist-variables "^6.18.0" + babel-runtime "^6.11.6" + babel-template "^6.14.0" + +babel-plugin-transform-es2015-modules-umd@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.18.0.tgz#23351770ece5c1f8e83ed67cb1d7992884491e50" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.18.0" + babel-runtime "^6.0.0" + babel-template "^6.8.0" + +babel-plugin-transform-es2015-object-super@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.8.0.tgz#1b858740a5a4400887c23dcff6f4d56eea4a24c5" + dependencies: + babel-helper-replace-supers "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-parameters@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.18.0.tgz#9b2cfe238c549f1635ba27fc1daa858be70608b1" + dependencies: + babel-helper-call-delegate "^6.18.0" + babel-helper-get-function-arity "^6.18.0" + babel-runtime "^6.9.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + +babel-plugin-transform-es2015-shorthand-properties@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.18.0.tgz#e2ede3b7df47bf980151926534d1dd0cbea58f43" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-plugin-transform-es2015-spread@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.8.0.tgz#0217f737e3b821fa5a669f187c6ed59205f05e9c" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-sticky-regex@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.8.0.tgz#e73d300a440a35d5c64f5c2a344dc236e3df47be" + dependencies: + babel-helper-regex "^6.8.0" + babel-runtime "^6.0.0" + babel-types "^6.8.0" + +babel-plugin-transform-es2015-template-literals@^6.6.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.8.0.tgz#86eb876d0a2c635da4ec048b4f7de9dfc897e66b" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.18.0.tgz#0b14c48629c90ff47a0650077f6aa699bee35798" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-es2015-unicode-regex@^6.3.13: + version "6.11.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.11.0.tgz#6298ceabaad88d50a3f4f392d8de997260f6ef2c" + dependencies: + babel-helper-regex "^6.8.0" + babel-runtime "^6.0.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.8.0.tgz#db25742e9339eade676ca9acec46f955599a68a4" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.8.0" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-flow-strip-types@^6.3.13: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.18.0.tgz#4d3e642158661e9b40db457c004a30817fa32592" + dependencies: + babel-plugin-syntax-flow "^6.18.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-object-rest-spread@^6.19.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.19.0.tgz#f6ac428ee3cb4c6aa00943ed1422ce813603b34c" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-react-constant-elements@^6.5.0, babel-plugin-transform-react-constant-elements@^6.9.1: + version "6.9.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-constant-elements/-/babel-plugin-transform-react-constant-elements-6.9.1.tgz#125b86d96cb322e2139b607fd749ad5fbb17f005" + dependencies: + babel-runtime "^6.9.1" + +babel-plugin-transform-react-display-name@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.8.0.tgz#f7a084977383d728bdbdc2835bba0159577f660e" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-react-inline-elements@^6.6.5: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-inline-elements/-/babel-plugin-transform-react-inline-elements-6.8.0.tgz#fc2d8fec1f2f87e5c4961ac367610039f325bbe6" + dependencies: + babel-runtime "^6.0.0" + +babel-plugin-transform-react-jsx-self@^6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.11.0.tgz#605c9450c1429f97a930f7e1dfe3f0d9d0dbd0f4" + dependencies: + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.9.0" + +babel-plugin-transform-react-jsx-source@^6.3.13: + version "6.9.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.9.0.tgz#af684a05c2067a86e0957d4f343295ccf5dccf00" + dependencies: + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.9.0" + +babel-plugin-transform-react-jsx@^6.3.13: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.8.0.tgz#94759942f70af18c617189aa7f3593f1644a71ab" + dependencies: + babel-helper-builder-react-jsx "^6.8.0" + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.0.0" + +babel-plugin-transform-react-pure-class-to-function@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-pure-class-to-function/-/babel-plugin-transform-react-pure-class-to-function-1.0.1.tgz#32a649c97d653250b419cfd1489331b0290d9ee4" + dependencies: + babel-helper-is-react-class "^1.0.0" + +babel-plugin-transform-react-remove-prop-types@^0.2.5: + version "0.2.11" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.2.11.tgz#05eb7cc4670d6506d801680576589c7abcd51b00" + +babel-plugin-transform-regenerator@^6.16.0: + version "6.16.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.16.1.tgz#a75de6b048a14154aae14b0122756c5bed392f59" + dependencies: + babel-runtime "^6.9.0" + babel-types "^6.16.0" + private "~0.1.5" + +babel-plugin-transform-runtime@^6.15.0: + version "6.15.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.15.0.tgz#3d75b4d949ad81af157570273846fb59aeb0d57c" + dependencies: + babel-runtime "^6.9.0" + +babel-plugin-transform-strict-mode@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.18.0.tgz#df7cf2991fe046f44163dcd110d5ca43bc652b9d" + dependencies: + babel-runtime "^6.0.0" + babel-types "^6.18.0" + +babel-polyfill@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.16.0.tgz#2d45021df87e26a374b6d4d1a9c65964d17f2422" + dependencies: + babel-runtime "^6.9.1" + core-js "^2.4.0" + regenerator-runtime "^0.9.5" + +babel-preset-es2015@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.18.0.tgz#b8c70df84ec948c43dcf2bf770e988eb7da88312" + dependencies: + babel-plugin-check-es2015-constants "^6.3.13" + babel-plugin-transform-es2015-arrow-functions "^6.3.13" + babel-plugin-transform-es2015-block-scoped-functions "^6.3.13" + babel-plugin-transform-es2015-block-scoping "^6.18.0" + babel-plugin-transform-es2015-classes "^6.18.0" + babel-plugin-transform-es2015-computed-properties "^6.3.13" + babel-plugin-transform-es2015-destructuring "^6.18.0" + babel-plugin-transform-es2015-duplicate-keys "^6.6.0" + babel-plugin-transform-es2015-for-of "^6.18.0" + babel-plugin-transform-es2015-function-name "^6.9.0" + babel-plugin-transform-es2015-literals "^6.3.13" + babel-plugin-transform-es2015-modules-amd "^6.18.0" + babel-plugin-transform-es2015-modules-commonjs "^6.18.0" + babel-plugin-transform-es2015-modules-systemjs "^6.18.0" + babel-plugin-transform-es2015-modules-umd "^6.18.0" + babel-plugin-transform-es2015-object-super "^6.3.13" + babel-plugin-transform-es2015-parameters "^6.18.0" + babel-plugin-transform-es2015-shorthand-properties "^6.18.0" + babel-plugin-transform-es2015-spread "^6.3.13" + babel-plugin-transform-es2015-sticky-regex "^6.3.13" + babel-plugin-transform-es2015-template-literals "^6.6.0" + babel-plugin-transform-es2015-typeof-symbol "^6.18.0" + babel-plugin-transform-es2015-unicode-regex "^6.3.13" + babel-plugin-transform-regenerator "^6.16.0" + +babel-preset-es2016@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-preset-es2016/-/babel-preset-es2016-6.16.0.tgz#c7daf5feedeee99c867813bdf0d573d94ca12812" + dependencies: + babel-plugin-transform-exponentiation-operator "^6.3.13" + +babel-preset-react-optimize@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-react-optimize/-/babel-preset-react-optimize-1.0.1.tgz#c23509fba7cbc76d7de7050e7d26bcd22bc304e8" + dependencies: + babel-plugin-transform-react-constant-elements "^6.5.0" + babel-plugin-transform-react-inline-elements "^6.6.5" + babel-plugin-transform-react-pure-class-to-function "^1.0.1" + babel-plugin-transform-react-remove-prop-types "^0.2.5" + +babel-preset-react@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.16.0.tgz#aa117d60de0928607e343c4828906e4661824316" + dependencies: + babel-plugin-syntax-flow "^6.3.13" + babel-plugin-syntax-jsx "^6.3.13" + babel-plugin-transform-flow-strip-types "^6.3.13" + babel-plugin-transform-react-display-name "^6.3.13" + babel-plugin-transform-react-jsx "^6.3.13" + babel-plugin-transform-react-jsx-self "^6.11.0" + babel-plugin-transform-react-jsx-source "^6.3.13" + +babel-register@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.18.0.tgz#892e2e03865078dd90ad2c715111ec4449b32a68" + dependencies: + babel-core "^6.18.0" + babel-runtime "^6.11.6" + core-js "^2.4.0" + home-or-tmp "^2.0.0" + lodash "^4.2.0" + mkdirp "^0.5.1" + source-map-support "^0.4.2" + +babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.9.0, babel-runtime@^6.9.1: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.18.0.tgz#0f4177ffd98492ef13b9f823e9994a02584c9078" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.9.5" + +babel-template@^6.14.0, babel-template@^6.15.0, babel-template@^6.16.0, babel-template@^6.8.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.16.0.tgz#e149dd1a9f03a35f817ddbc4d0481988e7ebc8ca" + dependencies: + babel-runtime "^6.9.0" + babel-traverse "^6.16.0" + babel-types "^6.16.0" + babylon "^6.11.0" + lodash "^4.2.0" + +babel-traverse@^6.15.0, babel-traverse@^6.16.0, babel-traverse@^6.18.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.19.0.tgz#68363fb821e26247d52a519a84b2ceab8df4f55a" + dependencies: + babel-code-frame "^6.16.0" + babel-messages "^6.8.0" + babel-runtime "^6.9.0" + babel-types "^6.19.0" + babylon "^6.11.0" + debug "^2.2.0" + globals "^9.0.0" + invariant "^2.2.0" + lodash "^4.2.0" + +babel-types@^6.15.0, babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.8.0, babel-types@^6.9.0: + version "6.19.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.19.0.tgz#8db2972dbed01f1192a8b602ba1e1e4c516240b9" + dependencies: + babel-runtime "^6.9.1" + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^1.0.1" + +babylon@^6.11.0, babylon@^6.13.0: + version "6.14.1" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.14.1.tgz#956275fab72753ad9b3435d7afe58f8bf0a29815" + +balanced-match@^0.4.1, balanced-match@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + +base64-js@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" + +batch@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.5.3.tgz#3f3414f380321743bfc1042f9a83ff1d5824d464" + +bcrypt-pbkdf@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz#3ca76b85241c7170bf7d9703e7b9aa74630040d4" + dependencies: + tweetnacl "^0.14.3" + +big.js@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978" + +binary-extensions@^1.0.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +bluebird@^3.4.6: + version "3.4.6" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.6.tgz#01da8d821d87813d158967e743d5fe6c62cf8c0f" + +boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +bootstrap@^3.3.6: + version "3.3.7" + resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-3.3.7.tgz#5a389394549f23330875a3b150656574f8a9eb71" + +bowser@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.6.0.tgz#37fc387b616cb6aef370dab4d6bd402b74c5c54d" + +brace-expansion@^1.0.0: + version "1.1.6" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" + dependencies: + balanced-match "^0.4.1" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +browserify-zlib@~0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" + dependencies: + pako "~0.2.0" + +browserslist@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.4.0.tgz#9cfdcf5384d9158f5b70da2aa00b30e8ff019049" + dependencies: + caniuse-db "^1.0.30000539" + +buffer-shims@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + +buffer@^4.9.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-modules@^1.0.0, builtin-modules@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + +bytes@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.3.0.tgz#d5b680a165b6201739acb611542aabc2d8ceb070" + +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + +camel-case@3.0.x: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" + dependencies: + no-case "^2.2.0" + upper-case "^1.1.1" + +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + +camelcase@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + +caniuse-db@^1.0.30000539, caniuse-db@^1.0.30000578: + version "1.0.30000592" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000592.tgz#7b916023941df4063d9d946a1f9ad0d5edaf2bcd" + +caseless@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + +center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + +chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +change-emitter@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/change-emitter/-/change-emitter-0.1.2.tgz#6b88ca4d5d864e516f913421b11899a860aee8db" + +chart.js@^2.1.6: + version "2.4.0" + resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.4.0.tgz#44198073f0f43e5e16662e108420d92652a3c9a3" + dependencies: + chartjs-color "^2.0.0" + moment "^2.10.6" + +chartjs-color-string@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/chartjs-color-string/-/chartjs-color-string-0.4.0.tgz#57748d4530ae28d8db0a5492182ba06dfdf2f468" + dependencies: + color-name "^1.0.0" + +chartjs-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chartjs-color/-/chartjs-color-2.0.0.tgz#7f60c7256589b24914814ece757659117381e35b" + dependencies: + chartjs-color-string "^0.4.0" + color-convert "^0.5.3" + +chokidar@^1.0.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +circular-json@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" + +clap@^1.0.9: + version "1.1.2" + resolved "https://registry.yarnpkg.com/clap/-/clap-1.1.2.tgz#316545bf22229225a2cecaa6824cd2f56a9709ed" + dependencies: + chalk "^1.1.3" + +classnames@^2.2.0, classnames@^2.2.5: + version "2.2.5" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" + +clean-css@3.4.x: + version "3.4.21" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.21.tgz#2101d5dbd19d63dbc16a75ebd570e7c33948f65b" + dependencies: + commander "2.8.x" + source-map "0.4.x" + +cli-cursor@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + dependencies: + restore-cursor "^1.0.1" + +cli-width@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" + +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +clone@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +coa@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.1.tgz#7f959346cfc8719e3f7233cd6852854a7c67d8a3" + dependencies: + q "^1.1.2" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +color-convert@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd" + +color-convert@^1.3.0: + version "1.8.2" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.8.2.tgz#be868184d7c8631766d54e7078e2672d7c7e3339" + dependencies: + color-name "^1.1.1" + +color-name@^1.0.0, color-name@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" + +color-string@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991" + dependencies: + color-name "^1.0.0" + +color@^0.11.0: + version "0.11.4" + resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764" + dependencies: + clone "^1.0.2" + color-convert "^1.3.0" + color-string "^0.3.0" + +colormin@^1.0.5: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133" + dependencies: + color "^0.11.0" + css-color-names "0.0.4" + has "^1.0.1" + +colors@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + dependencies: + delayed-stream "~1.0.0" + +commander@2.8.x: + version "2.8.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + dependencies: + graceful-readlink ">= 1.0.0" + +commander@2.9.x, commander@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + dependencies: + graceful-readlink ">= 1.0.0" + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + +component-emitter@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + +compressible@~2.0.8: + version "2.0.9" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.9.tgz#6daab4e2b599c2770dd9e21e7a891b1c5a755425" + dependencies: + mime-db ">= 1.24.0 < 2" + +compression@^1.5.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.6.2.tgz#cceb121ecc9d09c52d7ad0c3350ea93ddd402bc3" + dependencies: + accepts "~1.3.3" + bytes "2.3.0" + compressible "~2.0.8" + debug "~2.2.0" + on-headers "~1.0.1" + vary "~1.1.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.4.6: + version "1.5.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" + dependencies: + inherits "~2.0.1" + readable-stream "~2.0.0" + typedarray "~0.0.5" + +connect-history-api-fallback@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.3.0.tgz#e51d17f8f0ef0db90a64fdb47de3051556e9f169" + +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +constants-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-0.0.1.tgz#92577db527ba6c4cf0a4568d84bc031f441e21f2" + +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + +content-disposition@0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.1.tgz#87476c6a67c8daa87e32e87616df883ba7fb071b" + +content-type@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" + +convert-source-map@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.3.0.tgz#e9f3e9c6e2728efc2676696a70eb382f73106a67" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + +cookiejar@^2.0.6: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.0.tgz#86549689539b6d0e269b6637a304be508194d898" + +core-js@^1.0.0: + version "1.2.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + +core-js@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cosmiconfig@^2.1.0, cosmiconfig@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-2.1.1.tgz#817f2c2039347a1e9bf7d090c0923e53f749ca82" + dependencies: + js-yaml "^3.4.3" + minimist "^1.2.0" + object-assign "^4.1.0" + os-homedir "^1.0.1" + parse-json "^2.2.0" + require-from-string "^1.1.0" + +cross-spawn@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +crypto-browserify@~3.2.6: + version "3.2.8" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.2.8.tgz#b9b11dbe6d9651dd882a01e6cc467df718ecf189" + dependencies: + pbkdf2-compat "2.0.1" + ripemd160 "0.2.0" + sha.js "2.2.6" + +css-color-names@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" + +css-loader@^0.26.1: + version "0.26.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.26.1.tgz#2ba7f20131b93597496b3e9bb500785a49cd29ea" + dependencies: + babel-code-frame "^6.11.0" + css-selector-tokenizer "^0.7.0" + cssnano ">=2.6.1 <4" + loader-utils "~0.2.2" + lodash.camelcase "^4.3.0" + object-assign "^4.0.1" + postcss "^5.0.6" + postcss-modules-extract-imports "^1.0.0" + postcss-modules-local-by-default "^1.0.1" + postcss-modules-scope "^1.0.0" + postcss-modules-values "^1.1.0" + source-list-map "^0.1.4" + +css-select@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + +css-selector-tokenizer@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.6.0.tgz#6445f582c7930d241dcc5007a43d6fcb8f073152" + dependencies: + cssesc "^0.1.0" + fastparse "^1.1.1" + regexpu-core "^1.0.0" + +css-selector-tokenizer@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86" + dependencies: + cssesc "^0.1.0" + fastparse "^1.1.1" + regexpu-core "^1.0.0" + +css-what@2.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" + +cssesc@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" + +"cssnano@>=2.6.1 <4": + version "3.8.1" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.8.1.tgz#008a482148ee948cf0af2ee6e44bd97c53f886ec" + dependencies: + autoprefixer "^6.3.1" + decamelize "^1.1.2" + defined "^1.0.0" + has "^1.0.1" + object-assign "^4.0.1" + postcss "^5.0.14" + postcss-calc "^5.2.0" + postcss-colormin "^2.1.8" + postcss-convert-values "^2.3.4" + postcss-discard-comments "^2.0.4" + postcss-discard-duplicates "^2.0.1" + postcss-discard-empty "^2.0.1" + postcss-discard-overridden "^0.1.1" + postcss-discard-unused "^2.2.1" + postcss-filter-plugins "^2.0.0" + postcss-merge-idents "^2.1.5" + postcss-merge-longhand "^2.0.1" + postcss-merge-rules "^2.0.3" + postcss-minify-font-values "^1.0.2" + postcss-minify-gradients "^1.0.1" + postcss-minify-params "^1.0.4" + postcss-minify-selectors "^2.0.4" + postcss-normalize-charset "^1.1.0" + postcss-normalize-url "^3.0.7" + postcss-ordered-values "^2.1.0" + postcss-reduce-idents "^2.2.2" + postcss-reduce-initial "^1.0.0" + postcss-reduce-transforms "^1.0.3" + postcss-svgo "^2.1.1" + postcss-unique-selectors "^2.0.2" + postcss-value-parser "^3.2.3" + postcss-zindex "^2.0.1" + +csso@~2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/csso/-/csso-2.2.1.tgz#51fbb5347e50e81e6ed51668a48490ae6fe2afe2" + dependencies: + clap "^1.0.9" + source-map "^0.5.3" + +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + dependencies: + array-find-index "^1.0.1" + +d@^0.1.1, d@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" + dependencies: + es5-ext "~0.10.2" + +damerau-levenshtein@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.3.tgz#ae4f4ce0b62acae10ff63a01bb08f652f5213af2" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + +debug@2.2.0, debug@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + dependencies: + ms "0.7.1" + +debug@^2.1.1, debug@^2.2.0: + version "2.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" + dependencies: + ms "0.7.2" + +decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +deep-extend@~0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +defined@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + +del@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +doctrine@1.5.0, doctrine@^1.2.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +dom-converter@~0.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.1.4.tgz#a45ef5727b890c9bffe6d7c876e7b19cb0e17f3b" + dependencies: + utila "~0.3" + +dom-helpers@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-2.4.0.tgz#9bb4b245f637367b1fa670274272aa28fe06c367" + +dom-serializer@0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" + dependencies: + domelementtype "~1.1.1" + entities "~1.1.1" + +domain-browser@^1.1.1: + version "1.1.7" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" + +domelementtype@1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" + +domelementtype@~1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" + +domhandler@2.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.1.0.tgz#d2646f5e57f6c3bab11cf6cb05d3c0acf7412594" + dependencies: + domelementtype "1" + +domutils@1.1: + version "1.1.6" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.1.6.tgz#bddc3de099b9a2efacc51c623f28f416ecc57485" + dependencies: + domelementtype "1" + +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + dependencies: + dom-serializer "0" + domelementtype "1" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + +encodeurl@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" + +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + dependencies: + iconv-lite "~0.4.13" + +enhanced-resolve@~0.9.0: + version "0.9.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.2.0" + tapable "^0.1.8" + +entities@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + +errno@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d" + dependencies: + prr "~0.0.0" + +error-ex@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.0.tgz#e67b43f3e82c96ea3a584ffee0b9fc3325d802d9" + dependencies: + is-arrayish "^0.2.1" + +es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.7: + version "0.10.12" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" + dependencies: + es6-iterator "2" + es6-symbol "~3.1" + +es6-iterator@2: + version "2.0.0" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac" + dependencies: + d "^0.1.1" + es5-ext "^0.10.7" + es6-symbol "3" + +es6-map@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.4.tgz#a34b147be224773a4d7da8072794cefa3632b897" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + es6-iterator "2" + es6-set "~0.1.3" + es6-symbol "~3.1.0" + event-emitter "~0.3.4" + +es6-set@~0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + es6-iterator "2" + es6-symbol "3" + event-emitter "~0.3.4" + +es6-symbol@3, es6-symbol@^3.0.2, es6-symbol@~3.1, es6-symbol@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + +es6-weak-map@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.1.tgz#0d2bbd8827eb5fb4ba8f97fbfea50d43db21ea81" + dependencies: + d "^0.1.1" + es5-ext "^0.10.8" + es6-iterator "2" + es6-symbol "3" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escope@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" + dependencies: + es6-map "^0.1.3" + es6-weak-map "^2.0.1" + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-config-standard-jsx@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/eslint-config-standard-jsx/-/eslint-config-standard-jsx-3.2.0.tgz#c240e26ed919a11a42aa4de8059472b38268d620" + +eslint-config-standard-react@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/eslint-config-standard-react/-/eslint-config-standard-react-4.2.0.tgz#d15fd25e837e20aff0db32f64fb55d11880eb8d0" + dependencies: + eslint-config-standard-jsx "^3.0.0" + +eslint-config-standard@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-6.2.1.tgz#d3a68aafc7191639e7ee441e7348739026354292" + +eslint-import-resolver-node@^0.2.0: + version "0.2.3" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz#5add8106e8c928db2cba232bcd9efa846e3da16c" + dependencies: + debug "^2.2.0" + object-assign "^4.0.1" + resolve "^1.1.6" + +eslint-loader@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-1.6.1.tgz#96c47c812772eeb077e3a81681818e671a2cabf5" + dependencies: + find-cache-dir "^0.1.1" + loader-utils "^0.2.7" + object-assign "^4.0.1" + object-hash "^1.1.4" + +eslint-module-utils@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.0.0.tgz#a6f8c21d901358759cdc35dbac1982ae1ee58bce" + dependencies: + debug "2.2.0" + pkg-dir "^1.0.0" + +eslint-plugin-import@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.2.0.tgz#72ba306fad305d67c4816348a4699a4229ac8b4e" + dependencies: + builtin-modules "^1.1.1" + contains-path "^0.1.0" + debug "^2.2.0" + doctrine "1.5.0" + eslint-import-resolver-node "^0.2.0" + eslint-module-utils "^2.0.0" + has "^1.0.1" + lodash.cond "^4.3.0" + minimatch "^3.0.3" + pkg-up "^1.0.0" + +eslint-plugin-jsx-a11y@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-3.0.1.tgz#38f22742a5752a8e72db693d7cd86e13a357da25" + dependencies: + damerau-levenshtein "^1.0.0" + jsx-ast-utils "^1.0.0" + object-assign "^4.0.1" + +eslint-plugin-promise@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.4.0.tgz#6ba9048c2df57be77d036e0c68918bc9b4fc4195" + +eslint-plugin-react@^6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-6.8.0.tgz#741ab5438a094532e5ce1bbb935d6832356f492d" + dependencies: + doctrine "^1.2.2" + jsx-ast-utils "^1.3.4" + +eslint-plugin-standard@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-2.0.1.tgz#3589699ff9c917f2c25f76a916687f641c369ff3" + +eslint@^3.11.1: + version "3.11.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.11.1.tgz#408be581041385cba947cd8d1cd2227782b55dbf" + dependencies: + babel-code-frame "^6.16.0" + chalk "^1.1.3" + concat-stream "^1.4.6" + debug "^2.1.1" + doctrine "^1.2.2" + escope "^3.6.0" + espree "^3.3.1" + estraverse "^4.2.0" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + glob "^7.0.3" + globals "^9.2.0" + ignore "^3.2.0" + imurmurhash "^0.1.4" + inquirer "^0.12.0" + is-my-json-valid "^2.10.0" + is-resolvable "^1.0.0" + js-yaml "^3.5.1" + json-stable-stringify "^1.0.0" + levn "^0.3.0" + lodash "^4.0.0" + mkdirp "^0.5.0" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.1" + pluralize "^1.2.1" + progress "^1.1.8" + require-uncached "^1.0.2" + shelljs "^0.7.5" + strip-bom "^3.0.0" + strip-json-comments "~1.0.1" + table "^3.7.8" + text-table "~0.2.0" + user-home "^2.0.0" + +espree@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.3.2.tgz#dbf3fadeb4ecb4d4778303e50103b3d36c88b89c" + dependencies: + acorn "^4.0.1" + acorn-jsx "^3.0.0" + +esprima@^2.6.0: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + +esrecurse@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" + dependencies: + estraverse "~4.1.0" + object-assign "^4.0.1" + +estraverse@^4.1.1, estraverse@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +estraverse@~4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" + +esutils@^2.0.0, esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +etag@~1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8" + +event-emitter@~0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" + dependencies: + d "~0.1.1" + es5-ext "~0.10.7" + +eventemitter3@1.x.x: + version "1.2.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" + +events@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + +eventsource@~0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-0.1.6.tgz#0acede849ed7dd1ccc32c811bb11b944d4f29232" + dependencies: + original ">=0.0.5" + +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +express@^4.13.3: + version "4.14.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.14.0.tgz#c1ee3f42cdc891fb3dc650a8922d51ec847d0d66" + dependencies: + accepts "~1.3.3" + array-flatten "1.1.1" + content-disposition "0.5.1" + content-type "~1.0.2" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "~2.2.0" + depd "~1.1.0" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.7.0" + finalhandler "0.5.0" + fresh "0.3.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.1" + path-to-regexp "0.1.7" + proxy-addr "~1.1.2" + qs "6.2.0" + range-parser "~1.2.0" + send "0.14.1" + serve-static "~1.11.1" + type-is "~1.6.13" + utils-merge "1.0.0" + vary "~1.1.0" + +extend@^3.0.0, extend@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extract-text-webpack-plugin@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/extract-text-webpack-plugin/-/extract-text-webpack-plugin-1.0.1.tgz#c95bf3cbaac49dc96f1dc6e072549fbb654ccd2c" + dependencies: + async "^1.5.0" + loader-utils "^0.2.3" + webpack-sources "^0.1.0" + +extsprintf@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" + +fast-levenshtein@~2.0.4: + version "2.0.5" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.5.tgz#bd33145744519ab1c36c3ee9f31f08e9079b67f2" + +fastparse@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8" + +faye-websocket@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + dependencies: + websocket-driver ">=0.5.1" + +faye-websocket@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.0.tgz#d9ccf0e789e7db725d74bc4877d23aa42972ac50" + dependencies: + websocket-driver ">=0.5.1" + +fbjs@^0.8.1, fbjs@^0.8.4, fbjs@^0.8.6: + version "0.8.6" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.6.tgz#7eb67d6986b2d5007a9b6e92e0e7cb6f75cad290" + dependencies: + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + ua-parser-js "^0.7.9" + +figures@^1.3.5: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + +file-loader@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.9.0.tgz#1d2daddd424ce6d1b07cfe3f79731bed3617ab42" + dependencies: + loader-utils "~0.2.5" + +filename-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +finalhandler@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.5.0.tgz#e9508abece9b6dba871a6942a1d7911b91911ac7" + dependencies: + debug "~2.2.0" + escape-html "~1.0.3" + on-finished "~2.3.0" + statuses "~1.3.0" + unpipe "~1.0.0" + +find-cache-dir@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" + dependencies: + commondir "^1.0.1" + mkdirp "^0.5.1" + pkg-dir "^1.0.0" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +flat-cache@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.1.tgz#6c837d6225a7de5659323740b36d5361f71691ff" + dependencies: + circular-json "^0.3.0" + del "^2.0.2" + graceful-fs "^4.1.2" + write "^0.2.1" + +flatten@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" + +flexboxgrid@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/flexboxgrid/-/flexboxgrid-6.3.1.tgz#e99898afc07b7047722bb81a958a5fba4d4e20fd" + +for-in@^0.1.5: + version "0.1.6" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8" + +for-own@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072" + dependencies: + for-in "^0.1.5" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@^2.1.1, form-data@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +formidable@^1.0.17: + version "1.0.17" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.0.17.tgz#ef5491490f9433b705faa77249c99029ae348559" + +forwarded@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" + +fresh@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0: + version "1.0.15" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.0.15.tgz#fa63f590f3c2ad91275e4972a6cea545fb0aae44" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.29" + +fstream-ignore@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +function-bind@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" + +gauge@~2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.6.0.tgz#d35301ad18e96902b4751dcbbe40f4218b942a46" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-color "^0.1.7" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +gauge@~2.7.1: + version "2.7.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.2.tgz#15cecc31b02d05345a5d6b0e171cdb3ad2307774" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + supports-color "^0.2.0" + wide-align "^1.1.0" + +gaze@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.2.tgz#847224677adb8870d679257ed3388fdb61e40105" + dependencies: + globule "^1.0.0" + +generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + +get-caller-file@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + +getpass@^0.1.1: + version "0.1.6" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@~7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^9.0.0, globals@^9.2.0: + version "9.14.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034" + +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +globule@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.1.0.tgz#c49352e4dc183d85893ee825385eb994bb6df45f" + dependencies: + glob "~7.1.1" + lodash "~4.16.4" + minimatch "~3.0.2" + +graceful-fs@^4.1.2: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + +har-validator@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + dependencies: + chalk "^1.1.1" + commander "^2.9.0" + is-my-json-valid "^2.12.4" + pinkie-promise "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-color@^0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" + dependencies: + function-bind "^1.0.2" + +hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +he@1.1.x: + version "1.1.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.0.tgz#29319d49beec13a9b1f3c4f9b2a6dde4859bb2a7" + +history@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/history/-/history-3.2.1.tgz#71c7497f4e6090363d19a6713bb52a1bfcdd99aa" + dependencies: + invariant "^2.2.1" + loose-envify "^1.2.0" + query-string "^4.2.2" + warning "^3.0.0" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +hoist-non-react-statics@^1.0.0, hoist-non-react-statics@^1.0.3, hoist-non-react-statics@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +hosted-git-info@^2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" + +html-comment-regex@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e" + +html-minifier@^3.1.0: + version "3.2.3" + resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.2.3.tgz#d2ff536e24d95726c332493d8f77d84dbed85372" + dependencies: + camel-case "3.0.x" + clean-css "3.4.x" + commander "2.9.x" + he "1.1.x" + ncname "1.0.x" + param-case "2.1.x" + relateurl "0.2.x" + uglify-js "2.7.x" + +html-webpack-plugin@^2.24.1: + version "2.24.1" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-2.24.1.tgz#7f45fc678f66eac2d433f22336b4399da023b57e" + dependencies: + bluebird "^3.4.6" + html-minifier "^3.1.0" + loader-utils "^0.2.16" + lodash "^4.16.4" + pretty-error "^2.0.2" + toposort "^1.0.0" + +html-webpack-template@^5.4.2: + version "5.5.0" + resolved "https://registry.yarnpkg.com/html-webpack-template/-/html-webpack-template-5.5.0.tgz#336bbdaafcd6c04ba947a83c2e72b9e8404cf2e0" + +htmlparser2@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.3.0.tgz#cc70d05a59f6542e43f0e685c982e14c924a9efe" + dependencies: + domelementtype "1" + domhandler "2.1" + domutils "1.1" + readable-stream "1.0" + +http-browserify@^1.3.2: + version "1.7.0" + resolved "https://registry.yarnpkg.com/http-browserify/-/http-browserify-1.7.0.tgz#33795ade72df88acfbfd36773cefeda764735b20" + dependencies: + Base64 "~0.2.0" + inherits "~2.0.1" + +http-errors@~1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750" + dependencies: + inherits "2.0.3" + setprototypeof "1.0.2" + statuses ">= 1.3.1 < 2" + +http-proxy-middleware@~0.17.1: + version "0.17.2" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.17.2.tgz#572d517a6d2fb1063a469de294eed96066352007" + dependencies: + http-proxy "^1.15.1" + is-glob "^3.0.0" + lodash "^4.16.2" + micromatch "^2.3.11" + +http-proxy@^1.15.1: + version "1.16.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.1.tgz#734b32de6ca0e36e51b59c1e0115ff860d7668fd" + dependencies: + eventemitter3 "1.x.x" + requires-port "1.x.x" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.0.tgz#b3ffdfe734b2a3d4a9efd58e8654c91fce86eafd" + +hyphenate-style-name@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b" + +iconv-lite@~0.4.13: + version "0.4.15" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" + +icss-replace-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.0.2.tgz#cb0b6054eb3af6edc9ab1d62d01933e2d4c8bfa5" + +ieee754@^1.1.4: + version "1.1.8" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + +ignore@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.0.tgz#8d88f03c3002a0ac52114db25d2c673b0bf1e435" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +in-publish@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51" + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + dependencies: + repeating "^2.0.0" + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + +ini@~1.3.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + +inline-style-prefixer@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-2.0.5.tgz#c153c7e88fd84fef5c602e95a8168b2770671fe7" + dependencies: + bowser "^1.0.0" + hyphenate-style-name "^1.0.1" + +inquirer@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" + dependencies: + ansi-escapes "^1.1.0" + ansi-regex "^2.0.0" + chalk "^1.0.0" + cli-cursor "^1.0.1" + cli-width "^2.0.0" + figures "^1.3.5" + lodash "^4.3.0" + readline2 "^1.0.1" + run-async "^0.1.0" + rx-lite "^3.1.2" + string-width "^1.0.1" + strip-ansi "^3.0.0" + through "^2.3.6" + +interpret@^0.6.4: + version "0.6.6" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b" + +interpret@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c" + +invariant@^2.0.0, invariant@^2.1.0, invariant@^2.2.0, invariant@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +ipaddr.js@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.1.1.tgz#c791d95f52b29c1247d5df80ada39b8a73647230" + +is-absolute-url@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.0.0.tgz#9c4b20b0e5c0cbef9a479a367ede6f991679f359" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.0.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" + +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + dependencies: + builtin-modules "^1.0.0" + +is-dotfile@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-extglob@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.0.tgz#33411a482b046bf95e6b0cb27ee2711af4cf15ad" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-glob@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + dependencies: + is-extglob "^2.1.0" + +is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: + version "2.15.0" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + +is-number@^2.0.2, is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + dependencies: + path-is-inside "^1.0.1" + +is-plain-obj@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-resolvable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" + dependencies: + tryit "^1.0.1" + +is-stream@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-svg@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9" + dependencies: + html-comment-regex "^1.1.0" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isomorphic-fetch@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" + dependencies: + node-fetch "^1.0.1" + whatwg-fetch ">=0.10.0" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +jodid25519@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" + dependencies: + jsbn "~0.1.0" + +js-base64@^2.1.9: + version "2.1.9" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce" + +js-tokens@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5" + +js-yaml@^3.4.3, js-yaml@^3.5.1: + version "3.7.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" + dependencies: + argparse "^1.0.7" + esprima "^2.6.0" + +js-yaml@~3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.6.1.tgz#6e5fe67d8b205ce4d22fad05b7781e8dadcc4b30" + dependencies: + argparse "^1.0.7" + esprima "^2.6.0" + +jsbn@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json-formatter-js@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/json-formatter-js/-/json-formatter-js-1.3.0.tgz#a6577ac03ae7876d492b0954bd4eff33c38cbc09" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json3@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + +json5@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsonpointer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.0.tgz#6661e161d2fc445f19f98430231343722e1fcbd5" + +jsprim@^1.2.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.3.1.tgz#2a7256f70412a29ee3670aaca625994c4dcff252" + dependencies: + extsprintf "1.0.2" + json-schema "0.2.3" + verror "1.3.6" + +jsx-ast-utils@^1.0.0, jsx-ast-utils@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.3.4.tgz#0257ed1cc4b1e65b39d7d9940f9fb4f20f7ba0a9" + dependencies: + acorn-jsx "^3.0.1" + object-assign "^4.1.0" + +keycode@^2.1.1, keycode@^2.1.2: + version "2.1.7" + resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.1.7.tgz#7b9255919f6cff562b09a064d222dca70b020f5c" + +kind-of@^3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.0.4.tgz#7b8ecf18a4e17f8269d73b501c9f232c96887a74" + dependencies: + is-buffer "^1.0.2" + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +loader-utils@0.2.x, loader-utils@^0.2.11, loader-utils@^0.2.15, loader-utils@^0.2.16, loader-utils@^0.2.3, loader-utils@^0.2.7, loader-utils@~0.2.2, loader-utils@~0.2.5: + version "0.2.16" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.16.tgz#f08632066ed8282835dff88dfb52704765adee6d" + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + object-assign "^4.0.1" + +lodash-es@^4.2.1: + version "4.17.2" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.2.tgz#59011b585166e613eb9dd5fc256b2cd1a30f3712" + +lodash.assign@^4.0.3, lodash.assign@^4.0.6, lodash.assign@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + +lodash.clonedeep@^4.3.2, lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + +lodash.cond@^4.3.0: + version "4.5.2" + resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5" + +lodash.differencewith@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.differencewith/-/lodash.differencewith-4.5.0.tgz#bafafbc918b55154e179176a00bb0aefaac854b7" + +lodash.indexof@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/lodash.indexof/-/lodash.indexof-4.0.5.tgz#53714adc2cddd6ed87638f893aa9b6c24e31ef3c" + +lodash.isequal@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.4.0.tgz#6295768e98e14dc15ce8d362ef6340db82852031" + +lodash.isfunction@^3.0.8: + version "3.0.8" + resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.8.tgz#4db709fc81bc4a8fd7127a458a5346c5cdce2c6b" + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + +lodash.merge@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" + +lodash.mergewith@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz#150cf0a16791f5903b8891eab154609274bdea55" + +lodash.pickby@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.pickby/-/lodash.pickby-4.6.0.tgz#7dea21d8c18d7703a27c704c15d3b84a67e33aff" + +lodash.throttle@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" + +lodash.unionwith@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.unionwith/-/lodash.unionwith-4.6.0.tgz#74d140b5ca8146e6c643c3724f5152538d9ac1f0" + +lodash@^4.0.0, lodash@^4.14.0, lodash@^4.16.2, lodash@^4.16.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0: + version "4.17.2" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.2.tgz#34a3055babe04ce42467b607d700072c7ff6bf42" + +lodash@~4.16.4: + version "4.16.6" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.6.tgz#d22c9ac660288f3843e16ba7d2b5d06cca27d777" + +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.0.tgz#6b26248c42f6d4fa4b0d8542f78edfcde35642a8" + dependencies: + js-tokens "^2.0.0" + +loud-rejection@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" + +lower-case@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.3.tgz#c92393d976793eee5ba4edb583cf8eae35bd9bfb" + +lru-cache@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" + dependencies: + pseudomap "^1.0.1" + yallist "^2.0.0" + +macaddress@^0.2.8: + version "0.2.8" + resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" + +map-obj@^1.0.0, map-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + +material-ui@^0.16.4: + version "0.16.4" + resolved "https://registry.yarnpkg.com/material-ui/-/material-ui-0.16.4.tgz#b1ff4ea57069a89611b7e02a83d47c649e13c798" + dependencies: + babel-runtime "^6.11.6" + inline-style-prefixer "^2.0.1" + keycode "^2.1.1" + lodash.merge "^4.6.0" + lodash.throttle "^4.1.1" + react-addons-create-fragment "^15.0.0" + react-addons-transition-group "^15.0.0" + react-event-listener "^0.4.0" + recompose "^0.20.2" + simple-assign "^0.1.0" + warning "^3.0.0" + +math-expression-evaluator@^1.2.14: + version "1.2.14" + resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.14.tgz#39511771ed9602405fba9affff17eb4d2a3843ab" + dependencies: + lodash.indexof "^4.0.5" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +memory-fs@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290" + +memory-fs@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.3.0.tgz#7bcc6b629e3a43e871d7e29aca6ae8a7f15cbb20" + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +meow@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + +methods@^1.1.1, methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +micromatch@^2.1.5, micromatch@^2.3.11: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +"mime-db@>= 1.24.0 < 2", mime-db@~1.25.0: + version "1.25.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.25.0.tgz#c18dbd7c73a5dbf6f44a024dc0d165a1e7b1c392" + +mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7: + version "2.1.13" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.13.tgz#e07aaa9c6c6b9a7ca3012c69003ad25a39e92a88" + dependencies: + mime-db "~1.25.0" + +mime@1.2.x: + version "1.2.11" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" + +mime@1.3.4, mime@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" + +minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" + dependencies: + brace-expansion "^1.0.0" + +minimist@0.0.8, minimist@~0.0.1: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.1.3, minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +moment-duration-format@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/moment-duration-format/-/moment-duration-format-1.3.0.tgz#541771b5f87a049cc65540475d3ad966737d6908" + +moment@^2.10.6, moment@^2.15.1: + version "2.17.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.17.1.tgz#fed9506063f36b10f066c8b59a144d7faebe1d82" + +ms@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + +ms@0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" + +mute-stream@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" + +nan@^2.3.0, nan@^2.3.2: + version "2.4.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.4.0.tgz#fb3c59d45fe4effe215f0b890f8adf6eb32d2232" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + +ncname@1.0.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ncname/-/ncname-1.0.0.tgz#5b57ad18b1ca092864ef62b0b1ed8194f383b71c" + dependencies: + xml-char-classes "^1.0.0" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +no-case@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.0.tgz#ca2825ccb76b18e6f79d573dcfbf1eace33dd164" + dependencies: + lower-case "^1.1.1" + +node-fetch@^1.0.1: + version "1.6.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + +node-gyp@^3.3.1: + version "3.4.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.4.0.tgz#dda558393b3ecbbe24c9e6b8703c71194c63fa36" + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + minimatch "^3.0.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3" + osenv "0" + path-array "^1.0.0" + request "2" + rimraf "2" + semver "2.x || 3.x || 4 || 5" + tar "^2.0.0" + which "1" + +node-libs-browser@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-0.6.0.tgz#244806d44d319e048bc8607b5cc4eaf9a29d2e3c" + dependencies: + assert "^1.1.1" + browserify-zlib "~0.1.4" + buffer "^4.9.0" + console-browserify "^1.1.0" + constants-browserify "0.0.1" + crypto-browserify "~3.2.6" + domain-browser "^1.1.1" + events "^1.0.0" + http-browserify "^1.3.2" + https-browserify "0.0.0" + os-browserify "~0.1.2" + path-browserify "0.0.0" + process "^0.11.0" + punycode "^1.2.4" + querystring-es3 "~0.2.0" + readable-stream "^1.1.13" + stream-browserify "^1.0.0" + string_decoder "~0.10.25" + timers-browserify "^1.0.1" + tty-browserify "0.0.0" + url "~0.10.1" + util "~0.10.3" + vm-browserify "0.0.4" + +node-pre-gyp@^0.6.29: + version "0.6.32" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.32.tgz#fc452b376e7319b3d255f5f34853ef6fd8fe1fd5" + dependencies: + mkdirp "~0.5.1" + nopt "~3.0.6" + npmlog "^4.0.1" + rc "~1.1.6" + request "^2.79.0" + rimraf "~2.5.4" + semver "~5.3.0" + tar "~2.2.1" + tar-pack "~3.3.0" + +node-sass@^3.13.0: + version "3.13.0" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-3.13.0.tgz#d08b95bdebf40941571bd2c16a9334b980f8924f" + dependencies: + async-foreach "^0.1.3" + chalk "^1.1.1" + cross-spawn "^3.0.0" + gaze "^1.0.0" + get-stdin "^4.0.1" + glob "^7.0.3" + in-publish "^2.0.0" + lodash.assign "^4.2.0" + lodash.clonedeep "^4.3.2" + meow "^3.7.0" + mkdirp "^0.5.1" + nan "^2.3.2" + node-gyp "^3.3.1" + npmlog "^4.0.0" + request "^2.61.0" + sass-graph "^2.1.1" + +node-uuid@^1.4.7: + version "1.4.7" + resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.7.tgz#6da5a17668c4b3dd59623bda11cf7fa4c1f60a6f" + +"nopt@2 || 3", nopt@~3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: + version "2.3.5" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.5.tgz#8d924f142960e1777e7ffe170543631cc7cb02df" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + +normalize-url@^1.4.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.8.0.tgz#a9550b079aa3523c85d78df24eef1959fce359ab" + dependencies: + object-assign "^4.0.1" + prepend-http "^1.0.0" + query-string "^4.1.0" + sort-keys "^1.0.0" + +"npmlog@0 || 1 || 2 || 3": + version "3.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-3.1.2.tgz#2d46fa874337af9498a2f12bb43d8d0be4a36873" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.6.0" + set-blocking "~2.0.0" + +npmlog@^4.0.0, npmlog@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.1.tgz#d14f503b4cd79710375553004ba96e6662fbc0b8" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.1" + set-blocking "~2.0.0" + +nth-check@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4" + dependencies: + boolbase "~1.0.0" + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +oauth-sign@~0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + +object-hash@^1.1.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.1.5.tgz#bdd844e030d0861b692ca175c6cab6868ec233d7" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + +once@^1.3.0, once@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" + dependencies: + wrappy "1" + +onetime@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + +open@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/open/-/open-0.0.5.tgz#42c3e18ec95466b6bf0dc42f3a2945c3f0cad8fc" + +optimist@~0.6.0, optimist@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +original@>=0.0.5: + version "1.0.0" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.0.tgz#9147f93fa1696d04be61e01bd50baeaca656bd3b" + dependencies: + url-parse "1.0.x" + +os-browserify@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.1.2.tgz#49ca0293e0b19590a5f5de10c7f265a617d8fe54" + +os-homedir@^1.0.0, os-homedir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + dependencies: + lcid "^1.0.0" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@0: + version "0.1.3" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.3.tgz#83cf05c6d6458fc4d5ac6362ea325d92f2754217" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +pako@~0.2.0: + version "0.2.9" + resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" + +param-case@2.1.x: + version "2.1.0" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.0.tgz#2619f90fd6c829ed0b958f1c84ed03a745a6d70a" + dependencies: + no-case "^2.2.0" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + +parseurl@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" + +path-array@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-array/-/path-array-1.0.1.tgz#7e2f0f35f07a2015122b868b7eac0eb2c4fec271" + dependencies: + array-index "^1.0.0" + +path-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +pbkdf2-compat@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pbkdf2-compat/-/pbkdf2-compat-2.0.1.tgz#b6e0c8fa99494d94e0511575802a59a5c142f288" + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pkg-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + dependencies: + find-up "^1.0.0" + +pkg-up@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-1.0.0.tgz#3e08fb461525c4421624a33b9f7e6d0af5b05a26" + dependencies: + find-up "^1.0.0" + +pluralize@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" + +postcss-calc@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e" + dependencies: + postcss "^5.0.2" + postcss-message-helpers "^2.0.0" + reduce-css-calc "^1.2.6" + +postcss-colormin@^2.1.8: + version "2.2.1" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.1.tgz#dc5421b6ae6f779ef6bfd47352b94abe59d0316b" + dependencies: + colormin "^1.0.5" + postcss "^5.0.13" + postcss-value-parser "^3.2.3" + +postcss-convert-values@^2.3.4: + version "2.5.0" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.5.0.tgz#570aceb04b3061fb25f6f46bd0329e7ab6263c0b" + dependencies: + postcss "^5.0.11" + postcss-value-parser "^3.1.2" + +postcss-discard-comments@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d" + dependencies: + postcss "^5.0.14" + +postcss-discard-duplicates@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.0.2.tgz#02be520e91571ffb10738766a981d5770989bb32" + dependencies: + postcss "^5.0.4" + +postcss-discard-empty@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz#d2b4bd9d5ced5ebd8dcade7640c7d7cd7f4f92b5" + dependencies: + postcss "^5.0.14" + +postcss-discard-overridden@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz#8b1eaf554f686fb288cd874c55667b0aa3668d58" + dependencies: + postcss "^5.0.16" + +postcss-discard-unused@^2.2.1: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz#bce30b2cc591ffc634322b5fb3464b6d934f4433" + dependencies: + postcss "^5.0.14" + uniqs "^2.0.0" + +postcss-filter-plugins@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz#6d85862534d735ac420e4a85806e1f5d4286d84c" + dependencies: + postcss "^5.0.4" + uniqid "^4.0.0" + +postcss-load-config@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-1.0.0.tgz#1399f60dcd6bd9c3124b2eb22960f77f9dc08b3d" + dependencies: + cosmiconfig "^2.1.0" + object-assign "^4.1.0" + postcss-load-options "^1.0.2" + postcss-load-plugins "^2.0.0" + +postcss-load-options@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/postcss-load-options/-/postcss-load-options-1.0.2.tgz#b99eb5759a588f4b2dd8b6471c6985f72060e7b0" + dependencies: + cosmiconfig "^2.1.0" + object-assign "^4.1.0" + +postcss-load-plugins@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-load-plugins/-/postcss-load-plugins-2.1.0.tgz#dbb6f46271df8d16e19b5d691ebda5175ce424a0" + dependencies: + cosmiconfig "^2.1.1" + object-assign "^4.1.0" + +postcss-loader@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-1.2.0.tgz#42f29c5526e0fafac7100a4aab4d7d4acb5143e9" + dependencies: + loader-utils "^0.2.16" + object-assign "^4.1.0" + postcss "^5.2.6" + postcss-load-config "^1.0.0" + +postcss-merge-idents@^2.1.5: + version "2.1.7" + resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270" + dependencies: + has "^1.0.1" + postcss "^5.0.10" + postcss-value-parser "^3.1.1" + +postcss-merge-longhand@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.1.tgz#ff59b5dec6d586ce2cea183138f55c5876fa9cdc" + dependencies: + postcss "^5.0.4" + +postcss-merge-rules@^2.0.3: + version "2.0.10" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.0.10.tgz#54b360be804e7e69a5c7222635247b92a3569e9b" + dependencies: + postcss "^5.0.4" + vendors "^1.0.0" + +postcss-message-helpers@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e" + +postcss-minify-font-values@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz#4b58edb56641eba7c8474ab3526cafd7bbdecb69" + dependencies: + object-assign "^4.0.1" + postcss "^5.0.4" + postcss-value-parser "^3.0.2" + +postcss-minify-gradients@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz#5dbda11373703f83cfb4a3ea3881d8d75ff5e6e1" + dependencies: + postcss "^5.0.12" + postcss-value-parser "^3.3.0" + +postcss-minify-params@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.0.5.tgz#82d602643b8616a61fb3634d7ede0289836d67f9" + dependencies: + alphanum-sort "^1.0.1" + postcss "^5.0.2" + postcss-value-parser "^3.0.2" + uniqs "^2.0.0" + +postcss-minify-selectors@^2.0.4: + version "2.0.7" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.0.7.tgz#bfb9248fe14db33770f036572de6b4897c48d81c" + dependencies: + alphanum-sort "^1.0.2" + has "^1.0.1" + postcss "^5.0.14" + postcss-selector-parser "^2.0.0" + +postcss-modules-extract-imports@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.0.1.tgz#8fb3fef9a6dd0420d3f6d4353cf1ff73f2b2a341" + dependencies: + postcss "^5.0.4" + +postcss-modules-local-by-default@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.1.1.tgz#29a10673fa37d19251265ca2ba3150d9040eb4ce" + dependencies: + css-selector-tokenizer "^0.6.0" + postcss "^5.0.4" + +postcss-modules-scope@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.0.2.tgz#ff977395e5e06202d7362290b88b1e8cd049de29" + dependencies: + css-selector-tokenizer "^0.6.0" + postcss "^5.0.4" + +postcss-modules-values@^1.1.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.2.2.tgz#f0e7d476fe1ed88c5e4c7f97533a3e772ad94ca1" + dependencies: + icss-replace-symbols "^1.0.2" + postcss "^5.0.14" + +postcss-normalize-charset@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1" + dependencies: + postcss "^5.0.5" + +postcss-normalize-url@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.7.tgz#6bd90d0a4bc5a1df22c26ea65c53257dc3829f4e" + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^1.4.0" + postcss "^5.0.14" + postcss-value-parser "^3.2.3" + +postcss-ordered-values@^2.1.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.2.tgz#be8b511741fab2dac8e614a2302e9d10267b0771" + dependencies: + postcss "^5.0.4" + postcss-value-parser "^3.0.1" + +postcss-reduce-idents@^2.2.2: + version "2.3.1" + resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.3.1.tgz#024e8e219f52773313408573db9645ba62d2d2fe" + dependencies: + postcss "^5.0.4" + postcss-value-parser "^3.0.2" + +postcss-reduce-initial@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.0.tgz#8f739b938289ef2e48936d7101783e4741ca9bbb" + dependencies: + postcss "^5.0.4" + +postcss-reduce-transforms@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz#ff76f4d8212437b31c298a42d2e1444025771ae1" + dependencies: + has "^1.0.1" + postcss "^5.0.8" + postcss-value-parser "^3.0.1" + +postcss-selector-parser@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.2.tgz#3d70f5adda130da51c7c0c2fc023f56b1374fe08" + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-svgo@^2.1.1: + version "2.1.5" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.5.tgz#46fc0363f01bab6a36a9abb01c229fcc45363094" + dependencies: + is-svg "^2.0.0" + postcss "^5.0.14" + postcss-value-parser "^3.2.3" + svgo "^0.7.0" + +postcss-unique-selectors@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz#981d57d29ddcb33e7b1dfe1fd43b8649f933ca1d" + dependencies: + alphanum-sort "^1.0.1" + postcss "^5.0.4" + uniqs "^2.0.0" + +postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" + +postcss-zindex@^2.0.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.2.0.tgz#d2109ddc055b91af67fc4cb3b025946639d2af22" + dependencies: + has "^1.0.1" + postcss "^5.0.4" + uniqs "^2.0.0" + +postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.5, postcss@^5.2.6: + version "5.2.6" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.6.tgz#a252cd67cd52585035f17e9ad12b35137a7bdd9e" + dependencies: + chalk "^1.1.3" + js-base64 "^2.1.9" + source-map "^0.5.6" + supports-color "^3.1.2" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +prepend-http@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +pretty-error@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.0.2.tgz#a7db19cbb529ca9f0af3d3a2f77d5caf8e5dec23" + dependencies: + renderkid "~2.0.0" + utila "~0.4" + +private@^0.1.6, private@~0.1.5: + version "0.1.6" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.6.tgz#55c6a976d0f9bafb9924851350fe47b9b5fbb7c1" + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +process@^0.11.0, process@~0.11.0: + version "0.11.9" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.9.tgz#7bd5ad21aa6253e7da8682264f1e11d11c0318c1" + +progress@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" + +promise@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf" + dependencies: + asap "~2.0.3" + +proxy-addr@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.2.tgz#b4cc5f22610d9535824c123aef9d3cf73c40ba37" + dependencies: + forwarded "~0.1.0" + ipaddr.js "1.1.1" + +prr@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" + +pseudomap@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + +punycode@^1.2.4, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +q@^1.1.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" + +qs@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.0.tgz#3b7848c03c2dece69a9522b0fae8c4126d745f3b" + +qs@^6.1.0, qs@~6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" + +query-string@^4.1.0, query-string@^4.2.2: + version "4.2.3" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.2.3.tgz#9f27273d207a25a8ee4c7b8c74dcd45d556db822" + dependencies: + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +querystring-es3@~0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + +querystringify@0.0.x: + version "0.0.4" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-0.0.4.tgz#0cf7f84f9463ff0ae51c4c4b142d95be37724d9c" + +randomatic@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" + dependencies: + is-number "^2.0.2" + kind-of "^3.0.2" + +range-parser@^1.0.3, range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +rc@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.6.tgz#43651b76b6ae53b5c802f1151fa3fc3b059969c9" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~1.0.4" + +react-addons-create-fragment@^15.0.0: + version "15.4.1" + resolved "https://registry.yarnpkg.com/react-addons-create-fragment/-/react-addons-create-fragment-15.4.1.tgz#596fde66cf7f375b5dad3c36ff6efe19c0ac47e7" + +react-addons-perf@^15.4.1: + version "15.4.1" + resolved "https://registry.yarnpkg.com/react-addons-perf/-/react-addons-perf-15.4.1.tgz#c6dd5a7011f43cd3222f47b7cb1aebe9d4174cb0" + +"react-addons-shallow-compare@^0.14.0 || ^15.0.0": + version "15.4.1" + resolved "https://registry.yarnpkg.com/react-addons-shallow-compare/-/react-addons-shallow-compare-15.4.1.tgz#b68103dd4d13144cb221065f6021de1822bd435a" + +react-addons-test-utils@^15.4.1: + version "15.4.1" + resolved "https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.4.1.tgz#1e4caab151bf27cce26df5f9cb714f4fd8359ae1" + +react-addons-transition-group@^15.0.0: + version "15.4.1" + resolved "https://registry.yarnpkg.com/react-addons-transition-group/-/react-addons-transition-group-15.4.1.tgz#27d92717089c5e2db202e654a85b76a41b703acc" + +react-bootstrap@^0.30.7: + version "0.30.7" + resolved "https://registry.yarnpkg.com/react-bootstrap/-/react-bootstrap-0.30.7.tgz#39da80088693ecb71e8e63b5bdc313571fd993d1" + dependencies: + babel-runtime "^6.11.6" + classnames "^2.2.5" + dom-helpers "^2.4.0" + invariant "^2.2.1" + keycode "^2.1.2" + react-overlays "^0.6.10" + react-prop-types "^0.4.0" + uncontrollable "^4.0.1" + warning "^3.0.0" + +react-dom@^15.4.1: + version "15.4.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.4.1.tgz#d54c913261aaedb17adc20410d029dcc18a1344a" + dependencies: + fbjs "^0.8.1" + loose-envify "^1.1.0" + object-assign "^4.1.0" + +react-event-listener@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.4.0.tgz#26c40ab18f9f0e0d8d1fed9c3465e79c0a99c9a5" + dependencies: + react-addons-shallow-compare "^0.14.0 || ^15.0.0" + warning "^3.0.0" + +react-flexbox-grid@^0.10.2: + version "0.10.2" + resolved "https://registry.yarnpkg.com/react-flexbox-grid/-/react-flexbox-grid-0.10.2.tgz#9de9b5d0b065adbb3b3b7e26033515abf9a9a2b4" + +react-hot-api@^0.4.5: + version "0.4.7" + resolved "https://registry.yarnpkg.com/react-hot-api/-/react-hot-api-0.4.7.tgz#a7e22a56d252e11abd9366b61264cf4492c58171" + +react-hot-loader@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-1.3.1.tgz#c95647ae78b73dfceff6ec71ffcb04182ff6daf9" + dependencies: + react-hot-api "^0.4.5" + source-map "^0.4.4" + +react-overlays@^0.6.10: + version "0.6.10" + resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.6.10.tgz#e7e52dad47f00a0fc784eb044428c3a9e874bfa3" + dependencies: + classnames "^2.2.5" + dom-helpers "^2.4.0" + react-prop-types "^0.4.0" + warning "^3.0.0" + +react-prop-types@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/react-prop-types/-/react-prop-types-0.4.0.tgz#f99b0bfb4006929c9af2051e7c1414a5c75b93d0" + dependencies: + warning "^3.0.0" + +react-redux@^4.4.6: + version "4.4.6" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-4.4.6.tgz#4b9d32985307a11096a2dd61561980044fcc6209" + dependencies: + hoist-non-react-statics "^1.0.3" + invariant "^2.0.0" + lodash "^4.2.0" + loose-envify "^1.1.0" + +react-router@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-3.0.0.tgz#3f313e4dbaf57048c48dd0a8c3cac24d93667dff" + dependencies: + history "^3.0.0" + hoist-non-react-statics "^1.2.0" + invariant "^2.2.1" + loose-envify "^1.2.0" + warning "^3.0.0" + +react-tap-event-plugin@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/react-tap-event-plugin/-/react-tap-event-plugin-2.0.1.tgz#316beb3bc6556e29ec869a7293e89c826a9074d2" + dependencies: + fbjs "^0.8.6" + +react-tooltip@^3.1.8: + version "3.2.2" + resolved "https://registry.yarnpkg.com/react-tooltip/-/react-tooltip-3.2.2.tgz#3a599c0eabbd9eb9597aa2d72b217fd7ba358767" + dependencies: + classnames "^2.2.0" + +react@^15.4.1: + version "15.4.1" + resolved "https://registry.yarnpkg.com/react/-/react-15.4.1.tgz#498e918602677a3983cd0fd206dfe700389a0dd6" + dependencies: + fbjs "^0.8.4" + loose-envify "^1.1.0" + object-assign "^4.1.0" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +readable-stream@1.0: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^1.0.27-1, readable-stream@^1.1.13: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5: + version "2.2.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readable-stream@~2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readable-stream@~2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +readline2@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + mute-stream "0.0.5" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + dependencies: + resolve "^1.1.6" + +recompose@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/recompose/-/recompose-0.20.2.tgz#113d6ac7e29ca664cfffec16b681ddddf15250bc" + dependencies: + change-emitter "^0.1.2" + fbjs "^0.8.1" + hoist-non-react-statics "^1.0.0" + symbol-observable "^0.2.4" + +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" + +reduce-css-calc@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" + dependencies: + balanced-match "^0.4.2" + math-expression-evaluator "^1.2.14" + reduce-function-call "^1.0.1" + +reduce-function-call@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.2.tgz#5a200bf92e0e37751752fe45b0ab330fd4b6be99" + dependencies: + balanced-match "^0.4.2" + +redux-saga@^0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/redux-saga/-/redux-saga-0.13.0.tgz#9294386550deb0d56bc9a1b3c90a613e7ddb6593" + +redux@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/redux/-/redux-3.6.0.tgz#887c2b3d0b9bd86eca2be70571c27654c19e188d" + dependencies: + lodash "^4.2.1" + lodash-es "^4.2.1" + loose-envify "^1.1.0" + symbol-observable "^1.0.2" + +regenerate@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" + +regenerator-runtime@^0.9.5: + version "0.9.6" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029" + +regex-cache@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + dependencies: + is-equal-shallow "^0.1.3" + is-primitive "^2.0.0" + +regexpu-core@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +relateurl@0.2.x: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + +renderkid@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.0.tgz#1859753e7a5adbf35443aba0d4e4579e78abee85" + dependencies: + css-select "^1.1.0" + dom-converter "~0.1" + htmlparser2 "~3.3.0" + strip-ansi "^3.0.0" + utila "~0.3" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +request@2, request@^2.61.0, request@^2.79.0: + version "2.79.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + qs "~6.3.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + uuid "^3.0.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-from-string@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-1.2.1.tgz#529c9ccef27380adfec9a2f965b649bbee636418" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + +require-uncached@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + +requires-port@1.0.x, requires-port@1.x.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + +resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + +resolve@^1.1.6: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + +right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + dependencies: + align-text "^0.1.1" + +rimraf@2, rimraf@^2.2.8, rimraf@~2.5.1, rimraf@~2.5.4: + version "2.5.4" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" + dependencies: + glob "^7.0.5" + +ripemd160@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-0.2.0.tgz#2bf198bde167cacfa51c0a928e84b68bbe171fce" + +run-async@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" + dependencies: + once "^1.3.0" + +rx-lite@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" + +sass-graph@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.1.2.tgz#965104be23e8103cb7e5f710df65935b317da57b" + dependencies: + glob "^7.0.0" + lodash "^4.0.0" + yargs "^4.7.1" + +sass-loader@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-4.0.2.tgz#a616eb770366543e64f547c8630f39c4da75f15d" + dependencies: + async "^2.0.1" + loader-utils "^0.2.15" + object-assign "^4.1.0" + +sax@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" + +"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + +send@0.14.1: + version "0.14.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.14.1.tgz#a954984325392f51532a7760760e459598c89f7a" + dependencies: + debug "~2.2.0" + depd "~1.1.0" + destroy "~1.0.4" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.7.0" + fresh "0.3.0" + http-errors "~1.5.0" + mime "1.3.4" + ms "0.7.1" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.3.0" + +serve-index@^1.7.2: + version "1.8.0" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.8.0.tgz#7c5d96c13fb131101f93c1c5774f8516a1e78d3b" + dependencies: + accepts "~1.3.3" + batch "0.5.3" + debug "~2.2.0" + escape-html "~1.0.3" + http-errors "~1.5.0" + mime-types "~2.1.11" + parseurl "~1.3.1" + +serve-static@~1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.11.1.tgz#d6cce7693505f733c759de57befc1af76c0f0805" + dependencies: + encodeurl "~1.0.1" + escape-html "~1.0.3" + parseurl "~1.3.1" + send "0.14.1" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +setprototypeof@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.2.tgz#81a552141ec104b88e89ce383103ad5c66564d08" + +sha.js@2.2.6: + version "2.2.6" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.2.6.tgz#17ddeddc5f722fb66501658895461977867315ba" + +shelljs@^0.7.5: + version "0.7.5" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.5.tgz#2eef7a50a21e1ccf37da00df767ec69e30ad0675" + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +simple-assign@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/simple-assign/-/simple-assign-0.1.0.tgz#17fd3066a5f3d7738f50321bb0f14ca281cc4baa" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +slice-ansi@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +sockjs-client@^1.0.3: + version "1.1.1" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.1.tgz#284843e9a9784d7c474b1571b3240fca9dda4bb0" + dependencies: + debug "^2.2.0" + eventsource "~0.1.6" + faye-websocket "~0.11.0" + inherits "^2.0.1" + json3 "^3.3.2" + url-parse "^1.1.1" + +sockjs@^0.3.15: + version "0.3.18" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.18.tgz#d9b289316ca7df77595ef299e075f0f937eb4207" + dependencies: + faye-websocket "^0.10.0" + uuid "^2.0.2" + +sort-keys@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" + dependencies: + is-plain-obj "^1.0.0" + +source-list-map@^0.1.4, source-list-map@~0.1.0: + version "0.1.7" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.7.tgz#d4b5ce2a46535c72c7e8527c71a77d250618172e" + +source-map-support@^0.4.2: + version "0.4.6" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.6.tgz#32552aa64b458392a85eab3b0b5ee61527167aeb" + dependencies: + source-map "^0.5.3" + +source-map@0.4.x, source-map@^0.4.4, source-map@~0.4.1: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + +source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + +spdx-correct@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" + dependencies: + spdx-license-ids "^1.0.2" + +spdx-expression-parse@~1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" + +spdx-license-ids@^1.0.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.10.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.10.1.tgz#30e1a5d329244974a1af61511339d595af6638b0" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jodid25519 "^1.0.0" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +"statuses@>= 1.3.1 < 2", statuses@~1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + +stream-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-1.0.0.tgz#bf9b4abfb42b274d751479e44e0ff2656b6f1193" + dependencies: + inherits "~2.0.1" + readable-stream "^1.0.27-1" + +stream-cache@~0.0.1: + version "0.0.2" + resolved "https://registry.yarnpkg.com/stream-cache/-/stream-cache-0.0.2.tgz#1ac5ad6832428ca55667dbdee395dad4e6db118f" + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^3.0.0" + +string_decoder@~0.10.25, string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +stringstream@~0.0.4: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + dependencies: + get-stdin "^4.0.1" + +strip-json-comments@~1.0.1, strip-json-comments@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" + +style-loader@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.13.1.tgz#468280efbc0473023cd3a6cd56e33b5a1d7fc3a9" + dependencies: + loader-utils "^0.2.7" + +superagent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.1.0.tgz#e05a03b630cd7b0a0e17c26543977fd4a35c3296" + dependencies: + component-emitter "^1.2.0" + cookiejar "^2.0.6" + debug "^2.2.0" + extend "^3.0.0" + form-data "^2.1.1" + formidable "^1.0.17" + methods "^1.1.1" + mime "^1.3.4" + qs "^6.1.0" + readable-stream "^2.0.5" + +supports-color@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^3.1.0, supports-color@^3.1.1, supports-color@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" + dependencies: + has-flag "^1.0.0" + +svgo@^0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.1.tgz#287320fed972cb097e72c2bb1685f96fe08f8034" + dependencies: + coa "~1.0.1" + colors "~1.1.2" + csso "~2.2.1" + js-yaml "~3.6.1" + mkdirp "~0.5.1" + sax "~1.2.1" + whet.extend "~0.9.9" + +symbol-observable@^0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-0.2.4.tgz#95a83db26186d6af7e7a18dbd9760a2f86d08f40" + +symbol-observable@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" + +table@^3.7.8: + version "3.8.3" + resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" + dependencies: + ajv "^4.7.0" + ajv-keywords "^1.0.0" + chalk "^1.1.1" + lodash "^4.0.0" + slice-ansi "0.0.4" + string-width "^2.0.0" + +tapable@^0.1.8, tapable@~0.1.8: + version "0.1.10" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4" + +tar-pack@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.3.0.tgz#30931816418f55afc4d21775afdd6720cee45dae" + dependencies: + debug "~2.2.0" + fstream "~1.0.10" + fstream-ignore "~1.0.5" + once "~1.3.3" + readable-stream "~2.1.4" + rimraf "~2.5.1" + tar "~2.2.1" + uid-number "~0.0.6" + +tar@^2.0.0, tar@~2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +timers-browserify@^1.0.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d" + dependencies: + process "~0.11.0" + +to-fast-properties@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" + +toposort@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.0.tgz#b66cf385a1a8a8e68e45b8259e7f55875e8b06ef" + +tough-cookie@~2.3.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" + dependencies: + punycode "^1.4.1" + +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + +tryit@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + +tunnel-agent@~0.4.1: + version "0.4.3" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.4" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.4.tgz#8c9dbfb52795686f166cd2023794bcf103d13c2b" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +type-is@~1.6.13: + version "1.6.14" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.13" + +typedarray@~0.0.5: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +ua-parser-js@^0.7.9: + version "0.7.12" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb" + +uglify-js@2.7.x, uglify-js@~2.7.3: + version "2.7.5" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8" + dependencies: + async "~0.2.6" + source-map "~0.5.1" + uglify-to-browserify "~1.0.0" + yargs "~3.10.0" + +uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + +uid-number@~0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +uncontrollable@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/uncontrollable/-/uncontrollable-4.0.3.tgz#06ec76cb9e02914756085d9cea0354fc746b09b4" + dependencies: + invariant "^2.1.0" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + +uniqid@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.0.tgz#33d9679f65022f48988a03fd24e7dcaf8f109eca" + dependencies: + macaddress "^0.2.8" + +uniqs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + +unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +upper-case@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" + +url-loader@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-0.5.7.tgz#67e8779759f8000da74994906680c943a9b0925d" + dependencies: + loader-utils "0.2.x" + mime "1.2.x" + +url-parse@1.0.x: + version "1.0.5" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.0.5.tgz#0854860422afdcfefeb6c965c662d4800169927b" + dependencies: + querystringify "0.0.x" + requires-port "1.0.x" + +url-parse@^1.1.1: + version "1.1.7" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.1.7.tgz#025cff999653a459ab34232147d89514cc87d74a" + dependencies: + querystringify "0.0.x" + requires-port "1.0.x" + +url@~0.10.1: + version "0.10.3" + resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +user-home@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" + dependencies: + os-homedir "^1.0.0" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +util@0.10.3, util@~0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + dependencies: + inherits "2.0.1" + +utila@~0.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.3.3.tgz#d7e8e7d7e309107092b05f8d9688824d633a4226" + +utila@~0.4: + version "0.4.0" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + +utils-merge@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" + +uuid@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" + +uuid@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" + +validate-npm-package-license@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + dependencies: + spdx-correct "~1.0.0" + spdx-expression-parse "~1.0.0" + +vary@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" + +vendors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.1.tgz#37ad73c8ee417fb3d580e785312307d274847f22" + +verror@1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" + dependencies: + extsprintf "1.0.2" + +vm-browserify@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + dependencies: + indexof "0.0.1" + +warning@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" + dependencies: + loose-envify "^1.0.0" + +watchpack@^0.2.1: + version "0.2.9" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-0.2.9.tgz#62eaa4ab5e5ba35fdfc018275626e3c0f5e3fb0b" + dependencies: + async "^0.9.0" + chokidar "^1.0.0" + graceful-fs "^4.1.2" + +webpack-core@~0.6.0: + version "0.6.8" + resolved "https://registry.yarnpkg.com/webpack-core/-/webpack-core-0.6.8.tgz#edf9135de00a6a3c26dd0f14b208af0aa4af8d0a" + dependencies: + source-list-map "~0.1.0" + source-map "~0.4.1" + +webpack-dev-middleware@^1.4.0: + version "1.8.4" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.8.4.tgz#e8765c9122887ce9e3abd4cc9c3eb31b61e0948d" + dependencies: + memory-fs "~0.3.0" + mime "^1.3.4" + path-is-absolute "^1.0.0" + range-parser "^1.0.3" + +webpack-dev-server@^1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-1.16.2.tgz#8bebc2c4ce1c45a15c72dd769d9ba08db306a793" + dependencies: + compression "^1.5.2" + connect-history-api-fallback "^1.3.0" + express "^4.13.3" + http-proxy-middleware "~0.17.1" + open "0.0.5" + optimist "~0.6.1" + serve-index "^1.7.2" + sockjs "^0.3.15" + sockjs-client "^1.0.3" + stream-cache "~0.0.1" + strip-ansi "^3.0.0" + supports-color "^3.1.1" + webpack-dev-middleware "^1.4.0" + +webpack-merge@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-1.0.2.tgz#b28f4c895361f1a985a96952760d7170679779b4" + dependencies: + lodash.clonedeep "^4.5.0" + lodash.differencewith "^4.5.0" + lodash.isequal "^4.4.0" + lodash.isfunction "^3.0.8" + lodash.isplainobject "^4.0.6" + lodash.mergewith "^4.6.0" + lodash.unionwith "^4.6.0" + +webpack-sources@^0.1.0: + version "0.1.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.1.3.tgz#15ce2fb79d0a1da727444ba7c757bf164294f310" + dependencies: + source-list-map "~0.1.0" + source-map "~0.5.3" + +webpack@^1.13.1: + version "1.13.3" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-1.13.3.tgz#e79c46fe5a37c5ca70084ba0894c595cdcb42815" + dependencies: + acorn "^3.0.0" + async "^1.3.0" + clone "^1.0.2" + enhanced-resolve "~0.9.0" + interpret "^0.6.4" + loader-utils "^0.2.11" + memory-fs "~0.3.0" + mkdirp "~0.5.0" + node-libs-browser "^0.6.0" + optimist "~0.6.0" + supports-color "^3.1.0" + tapable "~0.1.8" + uglify-js "~2.7.3" + watchpack "^0.2.1" + webpack-core "~0.6.0" + +websocket-driver@>=0.5.1: + version "0.6.5" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36" + dependencies: + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7" + +whatwg-fetch@>=0.10.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.1.tgz#078b9461bbe91cea73cbce8bb122a05f9e92b772" + +whet.extend@~0.9.9: + version "0.9.9" + resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" + +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + +which@1, which@^1.2.9: + version "1.2.12" + resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" + dependencies: + isexe "^1.1.1" + +wide-align@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + dependencies: + string-width "^1.0.1" + +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + +window-size@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" + +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + dependencies: + mkdirp "^0.5.1" + +xml-char-classes@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/xml-char-classes/-/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d" + +xtend@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +yallist@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.0.0.tgz#306c543835f09ee1a4cb23b7bce9ab341c91cdd4" + +yargs-parser@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4" + dependencies: + camelcase "^3.0.0" + lodash.assign "^4.0.6" + +yargs@^4.7.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.8.1.tgz#c0c42924ca4aaa6b0e6da1739dfb216439f9ddc0" + dependencies: + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + lodash.assign "^4.0.3" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.1" + which-module "^1.0.0" + window-size "^0.2.0" + y18n "^3.2.1" + yargs-parser "^2.4.1" + +yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0" From d08d447d27f98576083a8ad4f34501e21d3b327f Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Tue, 6 Dec 2016 15:56:21 +0100 Subject: [PATCH 21/45] no more NomadLink --- frontend/package.json | 1 + .../AllocationFiles/AllocationFiles.js | 63 ++++--- .../AllocationInfo/AllocationInfo.js | 11 +- .../AllocationLink/AllocationLink.js | 32 ++++ .../AllocationList/AllocationList.js | 6 +- .../AllocationListRow/AllocationListRow.js | 46 +++-- .../components/AllocationRaw/AllocationRaw.js | 11 +- .../src/components/ClientLink/ClientLink.js | 58 ++++++ .../EvaluationLink/EvaluationLink.js | 32 ++++ .../EvaluationList/EvaluationList.js | 9 +- .../src/components/FormatTime/FormatTime.js | 4 +- frontend/src/components/JobInfo/JobInfo.js | 14 +- frontend/src/components/JobLink/JobLink.js | 47 +++++ .../components/JobTaskGroups/JobTaskGroups.js | 4 +- frontend/src/components/JobTasks/JobTasks.js | 19 +- .../src/components/NomadLink/NomadLink.js | 172 ------------------ .../src/components/ServerLink/ServerLink.js | 31 ++++ frontend/src/components/Topbar/Topbar.js | 17 +- frontend/src/containers/allocations.js | 4 +- frontend/src/containers/clients.js | 4 +- frontend/src/containers/events.js | 23 ++- frontend/src/containers/jobs.js | 4 +- frontend/src/containers/servers.js | 4 +- frontend/src/main.js | 7 +- 24 files changed, 346 insertions(+), 277 deletions(-) create mode 100644 frontend/src/components/AllocationLink/AllocationLink.js create mode 100644 frontend/src/components/ClientLink/ClientLink.js create mode 100644 frontend/src/components/EvaluationLink/EvaluationLink.js create mode 100644 frontend/src/components/JobLink/JobLink.js delete mode 100644 frontend/src/components/NomadLink/NomadLink.js create mode 100644 frontend/src/components/ServerLink/ServerLink.js diff --git a/frontend/package.json b/frontend/package.json index 171c1e43..3dbc5c8c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -46,6 +46,7 @@ "react-router": "^3.0.0", "react-tap-event-plugin": "^2.0.1", "react-tooltip": "^3.1.8", + "recompose": "^0.20.2", "redux": "^3.6.0", "redux-saga": "^0.13.0", "superagent": "^3.1.0" diff --git a/frontend/src/components/AllocationFiles/AllocationFiles.js b/frontend/src/components/AllocationFiles/AllocationFiles.js index 6e430042..cf085087 100644 --- a/frontend/src/components/AllocationFiles/AllocationFiles.js +++ b/frontend/src/components/AllocationFiles/AllocationFiles.js @@ -38,19 +38,6 @@ class AllocationFiles extends Component { } } - updateDimensions () { - const element = document.getElementById('file_browser_pane') - const positionInfo = element.getBoundingClientRect() - const width = positionInfo.width - 75 - - this.setState({ width }) - } - - componentDidMount () { - window.addEventListener('resize', this.updateDimensions) - this.updateDimensions() - } - componentWillReceiveProps (nextProps) { if (!this.findAllocNode(nextProps)) { return @@ -111,14 +98,19 @@ class AllocationFiles extends Component { } } + componentDidMount () { + window.addEventListener('resize', () => this.updateDimensions()) + this.updateDimensions() + } + componentWillUnmount () { - window.removeEventListener('resize', this.updateDimensions) + window.removeEventListener('resize', () => this.updateDimensions()) this.props.dispatch({ type: CLEAR_FILE_PATH }) - if (!this.state.fileWatching || !this.props.location.query.file) { + if (!this.state.fileWatching) { return } @@ -131,6 +123,14 @@ class AllocationFiles extends Component { }) } + updateDimensions () { + const element = document.getElementById('file_browser_pane') + const positionInfo = element.getBoundingClientRect() + const width = positionInfo.width - 75 + + this.setState({ width }) + } + findAllocNode (props) { // Find the node that this alloc belongs to const allocNode = props.nodes.find(node => node.ID === props.allocation.NodeID) @@ -203,14 +203,14 @@ class AllocationFiles extends Component { path = `${path}${file.Name}/` } - this.props.history.push({ + this.props.router.push({ pathname: this.props.location.pathname, query: { path } }) return } - this.props.history.push({ + this.props.router.push({ pathname: this.props.location.pathname, query: { path, @@ -219,11 +219,28 @@ class AllocationFiles extends Component { }) } + formatSizeUnits (bytes) { + if (bytes >= 1073741824) { + bytes = (bytes / 1073741824).toFixed(2) + ' GB' + } else if (bytes >= 1048576) { + bytes = (bytes / 1048576).toFixed(2) + ' MB' + } else if (bytes >= 1024) { + bytes = (bytes / 1024).toFixed(2) + ' KB' + } else if (bytes > 1) { + bytes = bytes + ' bytes' + } else if (bytes === 1) { + bytes = bytes + ' byte' + } else { + bytes = '0 byte' + } + return bytes + } + collectFiles () { const files = this.props.directory.map((file) => { const a = file.IsDir ? '/' : '' - const b = file.Name + ' ' + a - const c = file.IsDir ? ' - ' : file.Size + const b = file.Name + a + const c = file.IsDir ? '' : this.formatSizeUnits(file.Size) const i = file.IsDir ? folder : attachment @@ -295,6 +312,7 @@ class AllocationFiles extends Component { ) const title = Current path: {this.props.location.query.path || '/'} + const padding = { padding: 10 } return ( @@ -307,8 +325,8 @@ class AllocationFiles extends Component {
    -
    File: { fileName } { downloadBtn }
    -
    { this.content = c } }> +
    File: { fileName } { downloadBtn }
    +
    { this.content = c } }> { this.state.contents }
    @@ -330,7 +348,8 @@ AllocationFiles.propTypes = { dispatch: PropTypes.func.isRequired, file: PropTypes.object.isRequired, directory: PropTypes.array.isRequired, - history: PropTypes.object.isRequired + history: PropTypes.object.isRequired, + router: PropTypes.object.isRequired } export default connect(mapStateToProps)(AllocationFiles) diff --git a/frontend/src/components/AllocationInfo/AllocationInfo.js b/frontend/src/components/AllocationInfo/AllocationInfo.js index 1a100050..e5f48759 100644 --- a/frontend/src/components/AllocationInfo/AllocationInfo.js +++ b/frontend/src/components/AllocationInfo/AllocationInfo.js @@ -2,7 +2,8 @@ import React, { Component, PropTypes } from 'react' import { Card, CardTitle, CardText } from 'material-ui/Card' import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table' import { connect } from 'react-redux' -import NomadLink from '../NomadLink/NomadLink' +import JobLink from '../JobLink/JobLink' +import ClientLink from '../ClientLink/ClientLink' import MetaPayload from '../MetaPayload/MetaPayload' import FormatTime from '../FormatTime/FormatTime' @@ -114,15 +115,15 @@ class AllocationInfo extends Component { return
    Loading ...
    } - allocValues.Job = + allocValues.Job = allocValues.TaskGroup = ( - + {allocation.TaskGroup} - + ) - allocValues.Node = + allocValues.Node = const states = [] Object.keys(allocation.TaskStates || {}).forEach((key) => { diff --git a/frontend/src/components/AllocationLink/AllocationLink.js b/frontend/src/components/AllocationLink/AllocationLink.js new file mode 100644 index 00000000..6ce22e29 --- /dev/null +++ b/frontend/src/components/AllocationLink/AllocationLink.js @@ -0,0 +1,32 @@ +import React, { PureComponent, PropTypes } from 'react' +import { Link } from 'react-router' +import shortUUID from '../../helpers/uuid' + +class AllocationLink extends PureComponent { + + render () { + const linkAppend = this.props.linkAppend + const allocationId = this.props.allocationId + let children = this.props.children + + if (children === undefined) { + children = this.props.shortUUID ? shortUUID(allocationId) : allocationId + } + + return { children } + } +} + +AllocationLink.defaultProps = { + shortUUID: true, + linkAppend: '' +} + +AllocationLink.propTypes = { + children: PropTypes.array, + allocationId: PropTypes.string.isRequired, + linkAppend: PropTypes.string, + shortUUID: PropTypes.boolean.isRequired +} + +export default AllocationLink diff --git a/frontend/src/components/AllocationList/AllocationList.js b/frontend/src/components/AllocationList/AllocationList.js index f75ba65d..07291482 100644 --- a/frontend/src/components/AllocationList/AllocationList.js +++ b/frontend/src/components/AllocationList/AllocationList.js @@ -1,4 +1,4 @@ -import React, { Component, PropTypes } from 'react' +import React, { PureComponent, PropTypes } from 'react' import { Link } from 'react-router' import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow } from 'material-ui/Table' import SelectField from 'material-ui/SelectField' @@ -13,7 +13,7 @@ const clientHeaderColumn = display => const nodeIdToNameCache = {} -class AllocationList extends Component { +class AllocationList extends PureComponent { findNodeNameById (nodeId) { if (nodeId in nodeIdToNameCache) { @@ -177,7 +177,7 @@ class AllocationList extends Component { {this.filteredAllocations().map((allocation) => { - return + return })}
    ID
    { member.Name } { member.Addr } { member.Port }{ member.Tags.dc } { member.Tags.region }
    diff --git a/frontend/src/components/AllocationListRow/AllocationListRow.js b/frontend/src/components/AllocationListRow/AllocationListRow.js index cc78f73e..a4d90557 100644 --- a/frontend/src/components/AllocationListRow/AllocationListRow.js +++ b/frontend/src/components/AllocationListRow/AllocationListRow.js @@ -2,10 +2,13 @@ import FontIcon from 'material-ui/FontIcon' import React, { Component, PropTypes } from 'react' import ReactTooltip from 'react-tooltip' import { TableRow, TableRowColumn } from 'material-ui/Table' +import shallowEqual from 'recompose/shallowEqual' import AllocationStatusIcon from '../AllocationStatusIcon/AllocationStatusIcon' import FormatTime from '../FormatTime/FormatTime' -import NomadLink from '../NomadLink/NomadLink' +import ClientLink from '../ClientLink/ClientLink' +import AllocationLink from '../AllocationLink/AllocationLink' +import JobLink from '../JobLink/JobLink' const getAllocationNumberFromName = (allocationName) => { const match = /[\d+]/.exec(allocationName) @@ -13,16 +16,21 @@ const getAllocationNumberFromName = (allocationName) => { } const jobColumn = (allocation, display) => - (display ? : null) + (display + ? + + + + : null + ) -const clientColumn = (allocation, nodes, display) => +const clientColumn = (allocation, clients, display) => (display ? - + - : - null + : null ) const renderDesiredStatus = (allocation) => { @@ -42,6 +50,22 @@ const renderDesiredStatus = (allocation) => { class AllocationListRow extends Component { + shouldComponentUpdate (nextProps, nextState, nextContext) { + return ( + // if we don't got any nodes, and we are provided some nodes, update the component + (this.props.nodes.length === 0 && nextProps.nodes.length > 0) || + + // update if the allocation changed + !shallowEqual(this.props.allocation, nextProps.allocation) || + + // update on state change (could be removed, since we don't use state internally) + !shallowEqual(this.state, nextState) || + + // update on context change, (could be removed, don't think we use any state anyway) + !shallowEqual(this.context, nextContext) + ) + } + render () { const allocation = this.props.allocation const nodes = this.props.nodes @@ -54,13 +78,13 @@ class AllocationListRow extends Component { - + { jobColumn(allocation, showJobColumn) } - + { allocation.TaskGroup } (#{ getAllocationNumberFromName(allocation.Name) }) - + { renderDesiredStatus(allocation) } @@ -70,9 +94,9 @@ class AllocationListRow extends Component { - + format_align_left - + ) diff --git a/frontend/src/components/AllocationRaw/AllocationRaw.js b/frontend/src/components/AllocationRaw/AllocationRaw.js index 086698a5..4b2ac27e 100644 --- a/frontend/src/components/AllocationRaw/AllocationRaw.js +++ b/frontend/src/components/AllocationRaw/AllocationRaw.js @@ -1,12 +1,15 @@ import React, { PropTypes } from 'react' import { connect } from 'react-redux' - +import { Card, CardTitle, CardText } from 'material-ui/Card' import RawJson from '../RawJson/RawJson' const AllocationRaw = ({ allocation }) => -
    - -
    + + + + + + function mapStateToProps ({ allocation }) { return { allocation } diff --git a/frontend/src/components/ClientLink/ClientLink.js b/frontend/src/components/ClientLink/ClientLink.js new file mode 100644 index 00000000..abc2e8ad --- /dev/null +++ b/frontend/src/components/ClientLink/ClientLink.js @@ -0,0 +1,58 @@ +import React, { PureComponent, PropTypes } from 'react' +import { Link } from 'react-router' +import shortUUID from '../../helpers/uuid' + +const clientLookupCache = {} + +const findClientNameById = (clientId, clients) => { + if (clientId in clientLookupCache) { + return clientLookupCache[clientId] + } + + const r = Object.keys(clients).filter(node => clients[node].ID === clientId) + + if (r.length !== 0) { + clientLookupCache[clientId] = clients[r].Name + } else { + clientLookupCache[clientId] = false + } + + return clientLookupCache[clientId] +} + +class ClientLink extends PureComponent { + + render () { + const linkAppend = this.props.linkAppend + const clientId = this.props.clientId + let children = this.props.children + + if (children === undefined) { + if (this.props.clients.length > 0) { + children = findClientNameById(clientId, this.props.clients) + } + + if (!children) { + children = this.props.shortUUID ? shortUUID(clientId) : clientId + } + } + + return { children } + } +} + +ClientLink.defaultProps = { + clients: [], + shortUUID: true, + linkAppend: '' +} + +ClientLink.propTypes = { + children: PropTypes.array, + clientId: PropTypes.string.isRequired, + clients: PropTypes.array.isRequired, + linkAppend: PropTypes.string, + shortUUID: PropTypes.boolean.isRequired +} + +export default ClientLink diff --git a/frontend/src/components/EvaluationLink/EvaluationLink.js b/frontend/src/components/EvaluationLink/EvaluationLink.js new file mode 100644 index 00000000..80423387 --- /dev/null +++ b/frontend/src/components/EvaluationLink/EvaluationLink.js @@ -0,0 +1,32 @@ +import React, { PureComponent, PropTypes } from 'react' +import { Link } from 'react-router' +import shortUUID from '../../helpers/uuid' + +class EvaluationLink extends PureComponent { + + render () { + const evaluationId = this.props.evaluationId + let linkAppend = this.props.linkAppend + let children = this.props.children + + if (children === undefined) { + children = this.props.shortUUID ? shortUUID(evaluationId) : evaluationId + } + + return { children } + } +} + +EvaluationLink.defaultProps = { + linkAppend: '', + shortUUID: true +} + +EvaluationLink.propTypes = { + children: PropTypes.array, + evaluationId: PropTypes.string.isRequired, + linkAppend: PropTypes.string, + shortUUID: PropTypes.boolean.isRequired +} + +export default EvaluationLink diff --git a/frontend/src/components/EvaluationList/EvaluationList.js b/frontend/src/components/EvaluationList/EvaluationList.js index 4223637d..aeaadd40 100644 --- a/frontend/src/components/EvaluationList/EvaluationList.js +++ b/frontend/src/components/EvaluationList/EvaluationList.js @@ -1,5 +1,6 @@ import React, { PropTypes } from 'react' -import NomadLink from '../NomadLink/NomadLink' +import EvaluationLink from '../EvaluationLink/EvaluationLink' +import JobLink from '../JobLink/JobLink' const EvaluationList = ({ evaluations, containerClassName }) =>
    @@ -20,13 +21,13 @@ const EvaluationList = ({ evaluations, containerClassName }) => { evaluations.map(evaluation => - - + + { evaluation.Type } { evaluation.Priority } { evaluation.Status } { evaluation.StatusDescription } - + { evaluation.TriggeredBy } )} diff --git a/frontend/src/components/FormatTime/FormatTime.js b/frontend/src/components/FormatTime/FormatTime.js index 0aab7d97..08add5d1 100644 --- a/frontend/src/components/FormatTime/FormatTime.js +++ b/frontend/src/components/FormatTime/FormatTime.js @@ -1,11 +1,11 @@ -import React, { Component, PropTypes } from 'react' +import React, { PureComponent, PropTypes } from 'react' import ReactTooltip from 'react-tooltip' // eslint-disable-next-line no-unused-vars import momentDurationFormat from 'moment-duration-format' import moment from 'moment' import getMoment from '../../helpers/time' -class FormatTime extends Component { +class FormatTime extends PureComponent { getTimeDiff (time, now) { if (this.props.durationInterval && this.props.durationFormat) { diff --git a/frontend/src/components/JobInfo/JobInfo.js b/frontend/src/components/JobInfo/JobInfo.js index df69b5bf..61893320 100644 --- a/frontend/src/components/JobInfo/JobInfo.js +++ b/frontend/src/components/JobInfo/JobInfo.js @@ -1,7 +1,7 @@ import Paper from 'material-ui/Paper' import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' -import NomadLink from '../NomadLink/NomadLink' +import JobLink from '../JobLink/JobLink' import TableHelper from '../TableHelper/TableHelper' import MetaPayload from '../MetaPayload/MetaPayload' import ConstraintTable from '../ConstraintTable/ConstraintTable' @@ -21,14 +21,14 @@ class JobInfo extends Component { tasks.push( - + { taskGroup.Name } - + - + { task.Name } - + { task.Driver } { task.Resources.CPU } @@ -44,9 +44,9 @@ class JobInfo extends Component { return ( - + { taskGroup.Name } - + { taskGroup.Count } { taskGroup.Tasks.length } diff --git a/frontend/src/components/JobLink/JobLink.js b/frontend/src/components/JobLink/JobLink.js new file mode 100644 index 00000000..62d46d76 --- /dev/null +++ b/frontend/src/components/JobLink/JobLink.js @@ -0,0 +1,47 @@ +import React, { PureComponent, PropTypes } from 'react' +import { Link } from 'react-router' + +class JobLink extends PureComponent { + + render () { + const jobId = this.props.jobId + const JobIdUrl = encodeURIComponent(jobId) + const taskId = this.props.taskId + const taskGroupId = this.props.taskGroupId + + let linkAppend = this.props.linkAppend + let children = this.props.children + + if (taskId) { + if (!taskGroupId) { + throw new ('Cant link to a job taskId without a taskGroupId') + } + + linkAppend = linkAppend + '/tasks' + } + + if (taskGroupId) { + linkAppend = linkAppend + '/taskGroups' + } + + if (children === undefined) { + children = jobId + } + + return { children } + } +} + +JobLink.defaultProps = { + linkAppend: '' +} + +JobLink.propTypes = { + children: PropTypes.array, + jobId: PropTypes.string.isRequired, + taskId: PropTypes.string.isRequired, + linkAppend: PropTypes.string, + taskGroupId: PropTypes.string +} + +export default JobLink diff --git a/frontend/src/components/JobTaskGroups/JobTaskGroups.js b/frontend/src/components/JobTaskGroups/JobTaskGroups.js index 6587591b..92e29791 100644 --- a/frontend/src/components/JobTaskGroups/JobTaskGroups.js +++ b/frontend/src/components/JobTaskGroups/JobTaskGroups.js @@ -1,6 +1,6 @@ import React, { PropTypes } from 'react' import { connect } from 'react-redux' -import NomadLink from '../NomadLink/NomadLink' +import JobLink from '../JobLink/JobLink' import TableHelper from '../TableHelper/TableHelper' import RawJson from '../RawJson/RawJson' import MetaPayload from '../MetaPayload/MetaPayload' @@ -19,7 +19,7 @@ const JobTaskGroups = ({ job, location }) => { job.TaskGroups.forEach((taskGroup) => { taskGroups.push( - + { taskGroup.Name } { taskGroup.Count } diff --git a/frontend/src/components/JobTasks/JobTasks.js b/frontend/src/components/JobTasks/JobTasks.js index f2d38de1..1e7424cc 100644 --- a/frontend/src/components/JobTasks/JobTasks.js +++ b/frontend/src/components/JobTasks/JobTasks.js @@ -1,6 +1,6 @@ import React, { PropTypes } from 'react' import { connect } from 'react-redux' -import NomadLink from '../NomadLink/NomadLink' +import JobLink from '../JobLink/JobLink' import TableHelper from '../TableHelper/TableHelper' import RawJson from '../RawJson/RawJson' @@ -20,26 +20,15 @@ const JobTasks = ({ job, location }) => { taskGroup.Tasks.forEach((task) => { tasks.push( - - - + {task.Name} - - - { taskGroup.Name } - - + { taskGroup.Name } { task.Driver } { task.Resources.CPU } { task.Resources.MemoryMB } { task.Resources.DiskMB } - ) + ) }) }) diff --git a/frontend/src/components/NomadLink/NomadLink.js b/frontend/src/components/NomadLink/NomadLink.js deleted file mode 100644 index fbba588a..00000000 --- a/frontend/src/components/NomadLink/NomadLink.js +++ /dev/null @@ -1,172 +0,0 @@ -import React, { Component, PropTypes } from 'react' -import { Link } from 'react-router' -import shortUUID from '../../helpers/uuid' - -const nodeIdToNameCache = {} - -function NomadLinkException (message) { - this.message = message - this.name = 'NomadLinkException' -} - -export default class NomadLink extends Component { - - findNodeNameById (nodeId) { - if (nodeId in nodeIdToNameCache) { - return nodeIdToNameCache[nodeId] - } - - const r = Object.keys(this.props.nodeList) - .filter(node => - this.props.nodeList[node].ID === nodeId - ) - - if (r.length !== 0) { - nodeIdToNameCache[nodeId] = this.props.nodeList[r].Name - } else { - nodeIdToNameCache[nodeId] = false - } - - return nodeIdToNameCache[nodeId] - } - - render () { - const short = this.props.short === 'true' - const linkAppend = this.props.linkAppend || '' - - let children = this.props.children - const linkProps = Object.assign({}, this.props) - Object.keys(linkProps) - .filter(key => key.endsWith('Id')) - .forEach((key) => { - delete linkProps[key] - }) - - delete linkProps.short - delete linkProps.nodeList - delete linkProps.linkAppend - - // member - if (this.props.memberId !== undefined) { - const memberId = this.props.memberId - - if (children === undefined) { - children = short ? shortUUID(memberId) : memberId - } - - return ({ children }) - } - - // node - if (this.props.nodeId !== undefined) { - const nodeId = this.props.nodeId - if (children === undefined) { - if (this.props.nodeList) { - children = this.findNodeNameById(this.props.nodeId) - } - - if (!children) { - children = short ? shortUUID(nodeId) : nodeId - } - } - - return ({ children }) - } - - // eval - if (this.props.evalId !== undefined) { - const evalId = this.props.evalId - - if (children === undefined) { - children = short ? shortUUID(evalId) : evalId - } - - return ({ children }) - } - - // alloc - if (this.props.allocId !== undefined) { - const allocId = this.props.allocId - if (children === undefined) { - children = short ? shortUUID(allocId) : allocId - } - - return ({ children }) - } - - // tasks - if (this.props.taskId !== undefined) { - if (this.props.jobId !== undefined && this.props.taskGroupId !== undefined) { - const jobId = this.props.jobId - const jobIdUrl = encodeURIComponent(jobId) - const taskGroupId = this.props.taskGroupId - const taskId = this.props.taskId - - if (children === undefined) { - children = short ? shortUUID(taskId) : taskId - } - return ( - - { children } - - ) - } - - throw new NomadLinkException('NomadLink: You must also provide taskGroupId and jobId for task links!') - } - - // taskGroup (must be after task) - if (this.props.taskGroupId !== undefined) { - if (this.props.jobId !== undefined) { - const jobId = this.props.jobId - const jobIdUrl = encodeURIComponent(jobId) - const taskGroupId = this.props.taskGroupId - - if (children === undefined) { - children = short ? shortUUID(taskGroupId) : taskGroupId - } - - return ( - - { children } - - ) - } - - throw new NomadLinkException('NomadLink: You must also provide jobId for taskGroup links!') - } - - // job (must be after task & taskGroup - if (this.props.jobId !== undefined) { - const jobId = this.props.jobId - const jobIdUrl = encodeURIComponent(jobId) - - if (children === undefined) { - children = short ? shortUUID(jobId) : jobId - } - - return ({ children }) - } - - console.log(this.props) - throw new NomadLinkException('NomadLink: Unable to generate a link (check console for props)') - } -} - -NomadLink.propTypes = { - nodeList: PropTypes.array, - short: PropTypes.string, - children: PropTypes.oneOfType([ - PropTypes.array, - PropTypes.string, - React.PropTypes.node - ]), - memberId: PropTypes.string, - nodeId: PropTypes.string, - evalId: PropTypes.string, - allocId: PropTypes.string, - taskId: PropTypes.string, - jobId: PropTypes.string, - linkAppend: PropTypes.string, - taskGroupId: PropTypes.string -} diff --git a/frontend/src/components/ServerLink/ServerLink.js b/frontend/src/components/ServerLink/ServerLink.js new file mode 100644 index 00000000..623e6755 --- /dev/null +++ b/frontend/src/components/ServerLink/ServerLink.js @@ -0,0 +1,31 @@ +import React, { PureComponent, PropTypes } from 'react' +import { Link } from 'react-router' +import shortUUID from '../../helpers/uuid' + +class ServerLink extends PureComponent { + + render () { + const linkAppend = this.props.linkAppend + const serverId = this.props.serverId + let children = this.props.children + + if (children === undefined) { + children = this.props.shortUUID ? shortUUID(serverId) : serverId + } + + return { children } + } +} + +ServerLink.defaultProps = { + shortUUID: true, + linkAppend: '' +} + +ServerLink.propTypes = { + serverId: PropTypes.string.isRequired, + linkAppend: PropTypes.string, + shortUUID: PropTypes.boolean.isRequired +} + +export default ServerLink diff --git a/frontend/src/components/Topbar/Topbar.js b/frontend/src/components/Topbar/Topbar.js index d1d4f3c8..aeb52aef 100644 --- a/frontend/src/components/Topbar/Topbar.js +++ b/frontend/src/components/Topbar/Topbar.js @@ -5,6 +5,11 @@ import {Tabs, Tab} from 'material-ui/Tabs' class Topbar extends PureComponent { + constructor () { + super() + this._onClick = this.handleActive.bind(this) + } + handleActive (tab) { this.props.router.push(tab.props['data-route']) } @@ -44,12 +49,12 @@ class Topbar extends PureComponent {
    - - - - - - + + + + + +
    ) diff --git a/frontend/src/containers/allocations.js b/frontend/src/containers/allocations.js index 53751234..e4bad40a 100644 --- a/frontend/src/containers/allocations.js +++ b/frontend/src/containers/allocations.js @@ -1,8 +1,8 @@ -import React, { Component, PropTypes } from 'react' +import React, { PureComponent, PropTypes } from 'react' import { connect } from 'react-redux' import AllocationList from '../components/AllocationList/AllocationList' -class Allocations extends Component { +class Allocations extends PureComponent { render () { return diff --git a/frontend/src/containers/clients.js b/frontend/src/containers/clients.js index 679ac2b9..778178dc 100644 --- a/frontend/src/containers/clients.js +++ b/frontend/src/containers/clients.js @@ -1,6 +1,6 @@ import React, { PropTypes } from 'react' import { connect } from 'react-redux' -import NomadLink from '../components/NomadLink/NomadLink' +import ClientLink from '../components/ClientLink/ClientLink' import FormatBoolean from '../components/FormatBoolean/FormatBoolean' import NodeStatus from '../components/NodeStatus/NodeStatus' @@ -26,7 +26,7 @@ const Clients = ({ nodes }) => { nodes.map(node => - + { node.Name } diff --git a/frontend/src/containers/events.js b/frontend/src/containers/events.js index c05dc128..eaccce8b 100644 --- a/frontend/src/containers/events.js +++ b/frontend/src/containers/events.js @@ -1,6 +1,6 @@ import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' -import NomadLink from '../components/NomadLink/NomadLink' +import AllocationLink from '../components/AllocationLink/AllocationLink' import FormatTime from '../components/FormatTime/FormatTime' class Events extends Component { @@ -16,23 +16,22 @@ class Events extends Component { taskEvents.push( - + { allocation.JobID }.{ task } - + { event.Type } - { - event.KillError || - event.DriverError || - event.DownloadError || - event.RestartReason || - event.Message || - '' - } + { event.KillError || + event.DriverError || + event.DownloadError || + event.RestartReason || + event.Message || + '' + } - ) + ) }) }) } diff --git a/frontend/src/containers/jobs.js b/frontend/src/containers/jobs.js index ff111b84..268af7f2 100644 --- a/frontend/src/containers/jobs.js +++ b/frontend/src/containers/jobs.js @@ -2,7 +2,7 @@ import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' import { Link } from 'react-router' import { DropdownButton } from 'react-bootstrap' -import NomadLink from '../components/NomadLink/NomadLink' +import JobLink from '../components/JobLink/JobLink' const jobStatusColors = { running: '', @@ -146,7 +146,7 @@ class Jobs extends Component { { this.filteredJobs().map(job => - + { job.Status } { job.Type } { job.Priority } diff --git a/frontend/src/containers/servers.js b/frontend/src/containers/servers.js index 74802da5..aa3690a3 100644 --- a/frontend/src/containers/servers.js +++ b/frontend/src/containers/servers.js @@ -1,6 +1,6 @@ import React, { PropTypes } from 'react' import { connect } from 'react-redux' -import NomadLink from '../components/NomadLink/NomadLink' +import ServerLink from '../components/ServerLink/ServerLink' import FormatBoolean from '../components/FormatBoolean/FormatBoolean' const Servers = ({ members }) => { @@ -31,7 +31,7 @@ const Servers = ({ members }) => { { members.map((member) => { return ( - + { member.Name } { member.Addr } { member.Port } diff --git a/frontend/src/main.js b/frontend/src/main.js index 3798982a..1ec29379 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -3,14 +3,13 @@ import ReactDOM from 'react-dom' import { browserHistory } from 'react-router' import { Provider } from 'react-redux' -// import Perf from 'react-addons-perf'; -// import 'bootstrap/dist/css/bootstrap.min.css'; +import Perf from 'react-addons-perf' import '../assets/nomad-ui.css' import AppRouter from './router' import configureStore from './store' -// Perf.start(); +Perf.start() configureStore().then((store) => { ReactDOM.render( @@ -23,4 +22,4 @@ configureStore().then((store) => { console.log(err) }) -// window.Perf = Perf; +window.Perf = Perf From f450f73b50d38910a57b2dfea073ae7ceaef4aea Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Tue, 6 Dec 2016 16:59:57 +0100 Subject: [PATCH 22/45] re-style jobs list --- .../AllocationList/AllocationList.js | 41 +++-- frontend/src/components/JobLink/JobLink.js | 6 +- .../src/components/ServerLink/ServerLink.js | 3 +- frontend/src/containers/jobs.js | 143 ++++++++++-------- 4 files changed, 115 insertions(+), 78 deletions(-) diff --git a/frontend/src/components/AllocationList/AllocationList.js b/frontend/src/components/AllocationList/AllocationList.js index 07291482..6cec85d6 100644 --- a/frontend/src/components/AllocationList/AllocationList.js +++ b/frontend/src/components/AllocationList/AllocationList.js @@ -20,10 +20,7 @@ class AllocationList extends PureComponent { return nodeIdToNameCache[nodeId] } - const r = Object.keys(this.props.nodes) - .filter(node => - this.props.nodes[node].ID === nodeId - ) + const r = Object.keys(this.props.nodes).filter(node => this.props.nodes[node].ID === nodeId) if (r.length !== 0) { nodeIdToNameCache[nodeId] = this.props.nodes[r].Name @@ -64,12 +61,24 @@ class AllocationList extends PureComponent { return ( - - Any - - Running - Complete - Pending - Lost - Failed + + - Any - + + + Running + + + Complete + + + Pending + + + Lost + + + Failed + ) } @@ -93,14 +102,14 @@ class AllocationList extends PureComponent { .map((job) => { return ( - { job } + { job } ) }) jobs.unshift( - - Any - + - Any - ) @@ -129,14 +138,16 @@ class AllocationList extends PureComponent { .map((client) => { return ( - { this.findNodeNameById(client) } + + { this.findNodeNameById(client) } + ) }) clients.unshift( - - Any - + - Any - ) @@ -154,7 +165,7 @@ class AllocationList extends PureComponent { return (
    -
    +
    { this.clientFilter() }   { this.clientStatusFilter() } diff --git a/frontend/src/components/JobLink/JobLink.js b/frontend/src/components/JobLink/JobLink.js index 62d46d76..216d6fa6 100644 --- a/frontend/src/components/JobLink/JobLink.js +++ b/frontend/src/components/JobLink/JobLink.js @@ -14,7 +14,7 @@ class JobLink extends PureComponent { if (taskId) { if (!taskGroupId) { - throw new ('Cant link to a job taskId without a taskGroupId') + throw new Error('Cant link to a job taskId without a taskGroupId') } linkAppend = linkAppend + '/tasks' @@ -39,9 +39,9 @@ JobLink.defaultProps = { JobLink.propTypes = { children: PropTypes.array, jobId: PropTypes.string.isRequired, - taskId: PropTypes.string.isRequired, linkAppend: PropTypes.string, - taskGroupId: PropTypes.string + taskGroupId: PropTypes.string, + taskId: PropTypes.string.isRequired } export default JobLink diff --git a/frontend/src/components/ServerLink/ServerLink.js b/frontend/src/components/ServerLink/ServerLink.js index 623e6755..d21a2d2f 100644 --- a/frontend/src/components/ServerLink/ServerLink.js +++ b/frontend/src/components/ServerLink/ServerLink.js @@ -23,8 +23,9 @@ ServerLink.defaultProps = { } ServerLink.propTypes = { - serverId: PropTypes.string.isRequired, + children: PropTypes.array, linkAppend: PropTypes.string, + serverId: PropTypes.string.isRequired, shortUUID: PropTypes.boolean.isRequired } diff --git a/frontend/src/containers/jobs.js b/frontend/src/containers/jobs.js index 268af7f2..1e8479dd 100644 --- a/frontend/src/containers/jobs.js +++ b/frontend/src/containers/jobs.js @@ -1,22 +1,33 @@ import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' import { Link } from 'react-router' -import { DropdownButton } from 'react-bootstrap' +import SelectField from 'material-ui/SelectField' +import MenuItem from 'material-ui/MenuItem' +import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table' + import JobLink from '../components/JobLink/JobLink' -const jobStatusColors = { - running: '', - pending: 'warning', - dead: 'danger' +const columnFormat = { + width: 50, + maxWidth: 50, + overflow: 'inherit', + whiteSpace: 'normal' } -const summaryLabels = ['Starting', 'Running', 'Queued', 'Complete', 'Failed', 'Lost'] +const summaryLabels = [ + 'Starting', + 'Running', + 'Queued', + 'Complete', + 'Failed', + 'Lost' +] const getJobStatisticsHeader = () => { const output = [] summaryLabels.forEach((key) => { - output.push({ key }) + output.push({ key }) }) return output @@ -48,7 +59,7 @@ const getJobStatisticsRow = (job) => { const output = [] summaryLabels.forEach((key) => { - output.push({counter[key]}) + output.push({counter[key]}) }) return output @@ -77,16 +88,24 @@ class Jobs extends Component { let title = 'Job Type' if ('job_type' in query) { - title = {title}: { query.job_type } + title = { title }: { query.job_type } } return ( - -
  • - Any -
  • -
  • System
  • -
  • Batch
  • -
  • Service
  • -
    + + + - Any - + + + System + + + Batch + + + Service + + ) } @@ -96,16 +115,24 @@ class Jobs extends Component { let title = 'Job Status' if ('job_status' in query) { - title = {title}: { query.job_status } + title = { title }: { query.job_status } } return ( - -
  • - Any -
  • -
  • Running
  • -
  • Pending
  • -
  • Dead
  • -
    + + + - Any - + + + Running + + + Pending + + + Dead + + ) } @@ -120,45 +147,43 @@ class Jobs extends Component { } render () { + const flexibleWidth = { width: 300, minWidth: 300, overflow: 'display', whiteSpace: 'normal' } + return ( -
    -
    -
    -
    -

    Jobs

    - {this.jobStatusFilter()} -   - {this.jobTypeFilter()} -
    - -
    - - - - - - - - - { getJobStatisticsHeader() } - - - - { this.filteredJobs().map(job => - - - - - - - { getJobStatisticsRow(job) } - - )} - -
    IDStatusTypePriorityTask Groups
    { job.Status }{ job.Type }{ job.Priority }{ this.taskGroupCount(job) }
    -
    -
    +
    +
    + {this.jobStatusFilter()} +   + {this.jobTypeFilter()}
    + + + + + ID + Status + Type + Priority + Task Groups + { getJobStatisticsHeader() } + + + + { this.filteredJobs().map((job) => { + return ( + + + { job.Status } + { job.Type } + { job.Priority } + { this.taskGroupCount(job) } + { getJobStatisticsRow(job) } + + ) + }) + } + +
    ) } From 809c401630df10cb94a36e48a2dad49a430d3ce6 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Tue, 6 Dec 2016 17:32:03 +0100 Subject: [PATCH 23/45] initial style of Job Info page --- .../AllocationList/AllocationList.js | 4 + .../JobAllocations/JobAllocations.js | 10 +- frontend/src/components/JobInfo/JobInfo.js | 127 ++++++++++-------- .../components/ViewJobTopbar/ViewJobTopbar.js | 95 +++++++++++++ frontend/src/containers/allocation.js | 25 ---- frontend/src/containers/job.js | 31 ++--- 6 files changed, 187 insertions(+), 105 deletions(-) create mode 100644 frontend/src/components/ViewJobTopbar/ViewJobTopbar.js diff --git a/frontend/src/components/AllocationList/AllocationList.js b/frontend/src/components/AllocationList/AllocationList.js index 6cec85d6..67ff59e3 100644 --- a/frontend/src/components/AllocationList/AllocationList.js +++ b/frontend/src/components/AllocationList/AllocationList.js @@ -16,6 +16,10 @@ const nodeIdToNameCache = {} class AllocationList extends PureComponent { findNodeNameById (nodeId) { + if (this.props.nodes.length === 0) { + return nodeId; + } + if (nodeId in nodeIdToNameCache) { return nodeIdToNameCache[nodeId] } diff --git a/frontend/src/components/JobAllocations/JobAllocations.js b/frontend/src/components/JobAllocations/JobAllocations.js index 022e4374..6b1f73b5 100644 --- a/frontend/src/components/JobAllocations/JobAllocations.js +++ b/frontend/src/components/JobAllocations/JobAllocations.js @@ -5,21 +5,15 @@ import AllocationList from '../AllocationList/AllocationList' class JobAllocations extends PureComponent { render () { - const jobId = this.props.params.jobId - const allocs = this.props.allocations.filter(allocation => - allocation.JobID === jobId - ) + const allocs = this.props.allocations.filter(allocation => allocation.JobID === this.props.params.jobId) return ( -
    - -
    ) } } diff --git a/frontend/src/components/JobInfo/JobInfo.js b/frontend/src/components/JobInfo/JobInfo.js index 61893320..1a9f7de3 100644 --- a/frontend/src/components/JobInfo/JobInfo.js +++ b/frontend/src/components/JobInfo/JobInfo.js @@ -1,6 +1,8 @@ import Paper from 'material-ui/Paper' import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' +import { Grid, Row, Col } from 'react-flexbox-grid' +import { Card, CardTitle, CardText } from 'material-ui/Card' import JobLink from '../JobLink/JobLink' import TableHelper from '../TableHelper/TableHelper' import MetaPayload from '../MetaPayload/MetaPayload' @@ -58,66 +60,83 @@ class JobInfo extends Component { }) return ( -
    -
    - - Job Properties -
    - { jobProps.map((jobProp) => { - let jobPropValue = this.props.job[jobProp] - if (Array.isArray(jobPropValue)) { - jobPropValue = jobPropValue.join(', ') - } - - const result = [] - result.push(
    { jobProp }
    ) - result.push(
    { jobPropValue }
    ) + + + + + + +
    + { jobProps.map((jobProp) => { + let jobPropValue = this.props.job[jobProp] + if (Array.isArray(jobPropValue)) { + jobPropValue = jobPropValue.join(', ') + } - return result - }, this)} -
    - -
    - Meta Properties - -
    -
    + const result = [] + result.push(
    { jobProp }
    ) + result.push(
    { jobPropValue }
    ) -
    -
    - Constraints - -
    -
    - -
    -
    - Task Groups - { (taskGroups.length > 0) ? - + return result + }, this)} +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + { (taskGroups.length > 0) ? + : null } -
    -
    - -
    -
    - Tasks - { (tasks.length > 0) ? - + + + + + + + + + + { (tasks.length > 0) ? + : null } -
    -
    -
    + + + + + ) } } diff --git a/frontend/src/components/ViewJobTopbar/ViewJobTopbar.js b/frontend/src/components/ViewJobTopbar/ViewJobTopbar.js new file mode 100644 index 00000000..b6b953bb --- /dev/null +++ b/frontend/src/components/ViewJobTopbar/ViewJobTopbar.js @@ -0,0 +1,95 @@ +import FontIcon from 'material-ui/FontIcon' +import React, { PureComponent, PropTypes } from 'react' +import { BottomNavigation, BottomNavigationItem } from 'material-ui/BottomNavigation' +import { withRouter } from 'react-router' + +const infoIcon = info_outline +const allocationIcon = apps +const evaluationIcon = share +const taskGroupIcon = layers +const rawIcon = highlight + +class _ViewJobTopbar extends PureComponent { + + handleActive (tab) { + let path = location.pathname.split('/') + path.pop() + path = path.join('/') + this.props.router.push(path + '/' + tab) + } + + getActiveTab () { + const location = this.props.location + const end = location.pathname.split('/').pop() + + if (end.startsWith('info')) { + return 0 + } + + if (end.startsWith('allocations')) { + return 1 + } + + if (end.startsWith('evaluations')) { + return 2 + } + + if (end.startsWith('taskGroups')) { + return 3 + } + + if (end.startsWith('raw')) { + return 4 + } + + return 0 + } + + getStyle () { + return { + borderBottom: '1px solid #e0e0e0', + marginBottom: 10 + } + } + + render () { + return ( + + this.handleActive('info') } + /> + this.handleActive('allocations') } + /> + this.handleActive('evaluations') } + /> + this.handleActive('taskGroups') } + /> + this.handleActive('raw') } + /> + + ) + } +} + +_ViewJobTopbar.propTypes = { + router: PropTypes.object.isRequired, + location: PropTypes.object.isRequired +} + +const ViewJobTopbar = withRouter(_ViewJobTopbar) + +export default ViewJobTopbar diff --git a/frontend/src/containers/allocation.js b/frontend/src/containers/allocation.js index a060c01b..927b86e5 100644 --- a/frontend/src/containers/allocation.js +++ b/frontend/src/containers/allocation.js @@ -5,31 +5,6 @@ import { WATCH_ALLOC, UNWATCH_ALLOC } from '../sagas/event' class Allocation extends Component { - constructor (props) { - super(props) - - this.state = { - tabs: [ - { - name: 'Info', - path: 'info' - }, - { - name: 'Files', - path: 'files' - }, - { - name: 'Logs', - path: 'logs' - }, - { - name: 'Raw', - path: 'raw' - } - ] - } - } - componentWillMount () { this.props.dispatch({ type: WATCH_ALLOC, diff --git a/frontend/src/containers/job.js b/frontend/src/containers/job.js index 2af7162c..425321ee 100644 --- a/frontend/src/containers/job.js +++ b/frontend/src/containers/job.js @@ -1,6 +1,6 @@ import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' -import Tabs from '../components/Tabs/Tabs' +import ViewJobTopbar from '../components/ViewJobTopbar/ViewJobTopbar' import { WATCH_JOB, UNWATCH_JOB } from '../sagas/event' class Job extends Component { @@ -53,25 +53,20 @@ class Job extends Component { } render () { - if (this.props.job == null) return (null) - - const path = this.props.location.pathname - const tabSlug = path.split('/').pop() - const basePath = path.substring(0, path.lastIndexOf('/')) + if (this.props.job == null) { + return null + } return ( -
    -
    -
    -
    -

    Job: { this.props.job.ID }

    -
    -
    - - { this.props.children } - -
    -
    +
    + + +
    +

    Job: { this.props.job.Name }

    + +
    + + { this.props.children }
    ) From 8ef754766ee2aa39e47d107e8a09eb8d00b78d1c Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Tue, 6 Dec 2016 17:40:04 +0100 Subject: [PATCH 24/45] more styling of job info page --- frontend/assets/nomad-ui.css | 12 ++++++++++++ .../src/components/ConstraintRow/ConstraintRow.js | 4 ++-- .../components/ConstraintTable/ConstraintTable.js | 8 ++++---- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/frontend/assets/nomad-ui.css b/frontend/assets/nomad-ui.css index 4f50523f..6decc689 100644 --- a/frontend/assets/nomad-ui.css +++ b/frontend/assets/nomad-ui.css @@ -54,3 +54,15 @@ dd { white-space: pre; background: #f5f5f5; } + +code { + color: #c7254e; + background-color: #f9f2f4; + border-radius: 4px; + padding: 2px 4px; + font-size: 90%; +} + +th { + text-align: left +} diff --git a/frontend/src/components/ConstraintRow/ConstraintRow.js b/frontend/src/components/ConstraintRow/ConstraintRow.js index f5240482..2a2e1f06 100644 --- a/frontend/src/components/ConstraintRow/ConstraintRow.js +++ b/frontend/src/components/ConstraintRow/ConstraintRow.js @@ -5,7 +5,7 @@ const ConstraintRow = ({ constraint }) => { if (constraint.Operand === 'distinct_hosts') { return ( - Distinct Hosts + Distinct Hosts ) } @@ -13,7 +13,7 @@ const ConstraintRow = ({ constraint }) => { return ( { constraint.LTarget } - { constraint.Operand } + { constraint.Operand } { constraint.RTarget } ) diff --git a/frontend/src/components/ConstraintTable/ConstraintTable.js b/frontend/src/components/ConstraintTable/ConstraintTable.js index 728a1194..b4193b30 100644 --- a/frontend/src/components/ConstraintTable/ConstraintTable.js +++ b/frontend/src/components/ConstraintTable/ConstraintTable.js @@ -14,7 +14,7 @@ class ConstraintTable extends Component { } const table = ( - +
    @@ -29,10 +29,10 @@ class ConstraintTable extends Component { idPrefix={ this.props.idPrefix } constraint={ constraint } /> - )} + )}
    Key
    - ) + ) if (this.props.asTooltip) { return ( @@ -40,7 +40,7 @@ class ConstraintTable extends Component { { table } { this.props.constraints.length } constraints - +
    ) } From 9d966bac1e42eb5f7990385210957b14ffb3ceef Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Tue, 6 Dec 2016 17:57:09 +0100 Subject: [PATCH 25/45] make jslint pass --- frontend/assets/nomad-ui.css | 5 +- .../AllocationList/AllocationList.js | 2 +- .../ConstraintTable/ConstraintTable.js | 2 +- .../JobAllocations/JobAllocations.js | 10 +- frontend/src/components/JobInfo/JobInfo.js | 11 +- .../src/components/TableHelper/TableHelper.js | 9 +- frontend/src/containers/jobs.js | 13 +- frontend/webpack-prod.config.js | 133 ++++++++---------- 8 files changed, 94 insertions(+), 91 deletions(-) diff --git a/frontend/assets/nomad-ui.css b/frontend/assets/nomad-ui.css index 6decc689..8e3dae60 100644 --- a/frontend/assets/nomad-ui.css +++ b/frontend/assets/nomad-ui.css @@ -31,12 +31,13 @@ dl { dt { float: left; - width: 160px; + width: 200px; overflow: hidden; clear: left; text-align: right; text-overflow: ellipsis; white-space: nowrap; + font-weight: 500 } dt:after { @@ -44,7 +45,7 @@ dt:after { } dd { - margin-left: 180px; + margin-left: 220px; } .content-file { diff --git a/frontend/src/components/AllocationList/AllocationList.js b/frontend/src/components/AllocationList/AllocationList.js index 67ff59e3..f473a06c 100644 --- a/frontend/src/components/AllocationList/AllocationList.js +++ b/frontend/src/components/AllocationList/AllocationList.js @@ -17,7 +17,7 @@ class AllocationList extends PureComponent { findNodeNameById (nodeId) { if (this.props.nodes.length === 0) { - return nodeId; + return nodeId } if (nodeId in nodeIdToNameCache) { diff --git a/frontend/src/components/ConstraintTable/ConstraintTable.js b/frontend/src/components/ConstraintTable/ConstraintTable.js index b4193b30..b0cba334 100644 --- a/frontend/src/components/ConstraintTable/ConstraintTable.js +++ b/frontend/src/components/ConstraintTable/ConstraintTable.js @@ -14,7 +14,7 @@ class ConstraintTable extends Component { } const table = ( - +
    diff --git a/frontend/src/components/JobAllocations/JobAllocations.js b/frontend/src/components/JobAllocations/JobAllocations.js index 6b1f73b5..dbab2522 100644 --- a/frontend/src/components/JobAllocations/JobAllocations.js +++ b/frontend/src/components/JobAllocations/JobAllocations.js @@ -9,11 +9,11 @@ class JobAllocations extends PureComponent { return ( + showJobColumn={ false } + allocations={ allocs } + location={ this.props.location } + nodes={ this.props.nodes } + /> ) } } diff --git a/frontend/src/components/JobInfo/JobInfo.js b/frontend/src/components/JobInfo/JobInfo.js index 1a9f7de3..c3f0c5d2 100644 --- a/frontend/src/components/JobInfo/JobInfo.js +++ b/frontend/src/components/JobInfo/JobInfo.js @@ -1,4 +1,3 @@ -import Paper from 'material-ui/Paper' import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' import { Grid, Row, Col } from 'react-flexbox-grid' @@ -92,7 +91,7 @@ class JobInfo extends Component { - + @@ -102,12 +101,12 @@ class JobInfo extends Component { - + - { (taskGroups.length > 0) ? + { (taskGroups.length > 0) ? - + - { (tasks.length > 0) ? + { (tasks.length > 0) ? -
    Key
    - +
    + { headers.map(header => { header }) } - + { body }
    diff --git a/frontend/src/containers/jobs.js b/frontend/src/containers/jobs.js index 1e8479dd..472e874b 100644 --- a/frontend/src/containers/jobs.js +++ b/frontend/src/containers/jobs.js @@ -27,7 +27,13 @@ const getJobStatisticsHeader = () => { const output = [] summaryLabels.forEach((key) => { - output.push({ key }) + output.push( + + { key } + ) }) return output @@ -157,7 +163,10 @@ class Jobs extends Component { {this.jobTypeFilter()}
    - +
    ID diff --git a/frontend/webpack-prod.config.js b/frontend/webpack-prod.config.js index ba9155b4..3a18a9cb 100644 --- a/frontend/webpack-prod.config.js +++ b/frontend/webpack-prod.config.js @@ -8,78 +8,69 @@ const HtmlWebpackPlugin = require('html-webpack-plugin'); var webpackConfig = require("./webpack-base.config.js"); webpackConfig = merge(webpackConfig, { - output: { - filename: 'static/[name].[chunkhash].js', - chunkFilename: 'static/[name].[chunkhash].chunks.js' - }, - bail: true, - entry: [ - 'babel-polyfill', - './src/main.js' - ], - devtool: 'source-map', - module: { - loaders: [ - { - test: /\.css$/, - loader: ExtractTextPlugin.extract( - 'style', - 'css?-autoprefixer!postcss' - ) - }, - { - test: /\.jsx?$/, - exclude: /node_modules/, - loader: 'babel', - query: require('./config/babel.prod') - }, - { - test: /\.scss$/, - loader: ExtractTextPlugin.extract( - 'style', - 'css?-autprefixer!postcss!sass?outputStyle=expanded' - ) - } - ] - }, - plugins: [ - new webpack.DefinePlugin({'process.env.NODE_ENV': '"production"'}), - new ExtractTextPlugin('static/[name].[contenthash].css'), - new webpack.optimize.OccurenceOrderPlugin(), - new webpack.optimize.DedupePlugin(), - new webpack.optimize.UglifyJsPlugin({ - compressor: { - screw_ie8: true, - warnings: false - }, - mangle: { - screw_ie8: true - }, - output: { - comments: false, - screw_ie8: true - } - }), - new HtmlWebpackPlugin({ - title: 'Nomad UI', - inject: false, - favicon: './assets/img/favicon.png', - template: './index.html.ejs', - appMountId: 'app', - minify: { - removeComments: true, - collapseWhitespace: true, - removeRedundantAttributes: true, - useShortDoctype: true, - removeEmptyAttributes: true, - removeStyleLinkTypeAttributes: true, - keepClosingSlash: true, - minifyJS: true, - minifyCSS: true, - minifyURLs: true - } - }) + output: { + filename: 'static/[name].[chunkhash].js', + chunkFilename: 'static/[name].[chunkhash].chunks.js' + }, + bail: true, + entry: [ + 'babel-polyfill', + './src/main.js' + ], + devtool: 'source-map', + module: { + loaders: [ + { + test: /\.css$/, + loader: 'style!css!postcss', + exclude: /flexboxgrid/ + }, + { + test: /\.jsx?$/, + exclude: /node_modules/, + loader: 'babel', + query: require('./config/babel.prod') + } ] + }, + plugins: [ + new webpack.DefinePlugin({'process.env.NODE_ENV': '"production"'}), + new ExtractTextPlugin('static/[name].[contenthash].css'), + new webpack.optimize.OccurenceOrderPlugin(), + new webpack.optimize.DedupePlugin(), + new webpack.optimize.UglifyJsPlugin({ + compressor: { + screw_ie8: true, + warnings: false + }, + mangle: { + screw_ie8: true + }, + output: { + comments: false, + screw_ie8: true + } + }), + new HtmlWebpackPlugin({ + title: 'Nomad UI', + inject: false, + favicon: './assets/img/favicon.png', + template: './index.html.ejs', + appMountId: 'app', + minify: { + removeComments: true, + collapseWhitespace: true, + removeRedundantAttributes: true, + useShortDoctype: true, + removeEmptyAttributes: true, + removeStyleLinkTypeAttributes: true, + keepClosingSlash: true, + minifyJS: true, + minifyCSS: true, + minifyURLs: true + } + }) + ] }); module.exports = webpackConfig; From 09528c0297be02e983c2402fa1de2ccde1d44ca5 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Wed, 7 Dec 2016 11:10:15 +0100 Subject: [PATCH 26/45] more UI improvements --- frontend/.eslintrc.js | 21 +++-- .../AllocationInfo/AllocationInfo.js | 2 +- .../AllocationList/AllocationList.js | 64 ++++++++------- .../AllocationListRow/AllocationListRow.js | 4 +- frontend/src/components/JobInfo/JobInfo.js | 48 ++++++------ frontend/src/components/Table/Table.js | 27 +++++++ frontend/src/components/Table/TableBody.js | 13 ++++ frontend/src/components/Table/TableFooter.js | 7 ++ frontend/src/components/Table/TableHeader.js | 14 ++++ .../src/components/Table/TableHeaderColumn.js | 26 +++++++ frontend/src/components/Table/TableRow.js | 13 ++++ .../src/components/Table/TableRowColumn.js | 19 +++++ frontend/src/components/Table/index.js | 7 ++ .../src/components/TableHelper/TableHelper.js | 18 ++--- frontend/src/containers/jobs.js | 77 ++++++++++--------- 15 files changed, 254 insertions(+), 106 deletions(-) create mode 100644 frontend/src/components/Table/Table.js create mode 100644 frontend/src/components/Table/TableBody.js create mode 100644 frontend/src/components/Table/TableFooter.js create mode 100644 frontend/src/components/Table/TableHeader.js create mode 100644 frontend/src/components/Table/TableHeaderColumn.js create mode 100644 frontend/src/components/Table/TableRow.js create mode 100644 frontend/src/components/Table/TableRowColumn.js create mode 100644 frontend/src/components/Table/index.js diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js index 5a34757b..ac3c053d 100644 --- a/frontend/.eslintrc.js +++ b/frontend/.eslintrc.js @@ -1,13 +1,20 @@ module.exports = { - "env": { - "es6": true, - "browser": true, - "node": true + root: true, + env: { + es6: true, + browser: true, + node: true, }, - "parserOptions": { - "sourceType": "module", + extends: ['eslint:recommended', 'standard-react'], + parser: 'babel-eslint', + parserOptions: { + ecmaVersion: 7, + sourceType: 'module', + ecmaFeatures: { + jsx: true, + experimentalObjectRestSpread: true, + } }, - "extends": ["standard", "standard-react"], "rules": { 'indent': ['error', 2], 'no-constant-condition': ['error', { checkLoops: false }], diff --git a/frontend/src/components/AllocationInfo/AllocationInfo.js b/frontend/src/components/AllocationInfo/AllocationInfo.js index e5f48759..b170dfa1 100644 --- a/frontend/src/components/AllocationInfo/AllocationInfo.js +++ b/frontend/src/components/AllocationInfo/AllocationInfo.js @@ -1,6 +1,6 @@ import React, { Component, PropTypes } from 'react' import { Card, CardTitle, CardText } from 'material-ui/Card' -import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table' +import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from '../Table' import { connect } from 'react-redux' import JobLink from '../JobLink/JobLink' import ClientLink from '../ClientLink/ClientLink' diff --git a/frontend/src/components/AllocationList/AllocationList.js b/frontend/src/components/AllocationList/AllocationList.js index f473a06c..ab59a00e 100644 --- a/frontend/src/components/AllocationList/AllocationList.js +++ b/frontend/src/components/AllocationList/AllocationList.js @@ -1,8 +1,9 @@ import React, { PureComponent, PropTypes } from 'react' import { Link } from 'react-router' -import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow } from 'material-ui/Table' +import { Card, CardHeader, CardText } from 'material-ui/Card' import SelectField from 'material-ui/SelectField' import MenuItem from 'material-ui/MenuItem' +import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow } from '../Table' import AllocationListRow from '../AllocationListRow/AllocationListRow' const jobHeaderColumn = display => @@ -169,33 +170,40 @@ class AllocationList extends PureComponent { return (
    -
    - { this.clientFilter() } -   - { this.clientStatusFilter() } -   - { this.jobIdFilter() } -
    - -
    - - - - ID - { jobHeaderColumn(showJobColumn) } - Task Group - Status - { clientHeaderColumn(showClientColumn) } - Age - Actions - - - - {this.filteredAllocations().map((allocation) => { - return - })} - -
    + + + + { this.clientFilter() } +   + { this.clientStatusFilter() } +   + { this.jobIdFilter() } + + + + + + + + + + ID + { jobHeaderColumn(showJobColumn) } + Task Group + Status + { clientHeaderColumn(showClientColumn) } + Age + Actions + + + + {this.filteredAllocations().map((allocation) => { + return + })} + +
    +
    +
    ) } } diff --git a/frontend/src/components/AllocationListRow/AllocationListRow.js b/frontend/src/components/AllocationListRow/AllocationListRow.js index a4d90557..e1df47bc 100644 --- a/frontend/src/components/AllocationListRow/AllocationListRow.js +++ b/frontend/src/components/AllocationListRow/AllocationListRow.js @@ -1,7 +1,7 @@ import FontIcon from 'material-ui/FontIcon' import React, { Component, PropTypes } from 'react' import ReactTooltip from 'react-tooltip' -import { TableRow, TableRowColumn } from 'material-ui/Table' +import { TableRow, TableRowColumn } from '../Table' import shallowEqual from 'recompose/shallowEqual' import AllocationStatusIcon from '../AllocationStatusIcon/AllocationStatusIcon' @@ -73,7 +73,7 @@ class AllocationListRow extends Component { const showClientColumn = this.props.showClientColumn return ( - + diff --git a/frontend/src/components/JobInfo/JobInfo.js b/frontend/src/components/JobInfo/JobInfo.js index c3f0c5d2..837b853c 100644 --- a/frontend/src/components/JobInfo/JobInfo.js +++ b/frontend/src/components/JobInfo/JobInfo.js @@ -6,6 +6,7 @@ import JobLink from '../JobLink/JobLink' import TableHelper from '../TableHelper/TableHelper' import MetaPayload from '../MetaPayload/MetaPayload' import ConstraintTable from '../ConstraintTable/ConstraintTable' +import { TableRow, TableRowColumn } from '../Table' const jobProps = ['ID', 'Name', 'Region', 'Datacenters', 'Status', 'Priority'] @@ -20,41 +21,44 @@ class JobInfo extends Component { const taskGroups = job.TaskGroups.map((taskGroup) => { taskGroup.Tasks.map((task) => { tasks.push( - - + + { taskGroup.Name } - - + + { task.Name } - - { task.Driver } - { task.Resources.CPU } - { task.Resources.MemoryMB } - { task.Resources.DiskMB } - - - ) - return null + + { task.Driver } + { task.Resources.CPU } + { task.Resources.MemoryMB } + { task.Resources.DiskMB } + + + + + ) }) const taskGroupMeta = taskGroup.Meta || {} return ( - - + + { taskGroup.Name } - - { taskGroup.Count } - { taskGroup.Tasks.length } - - { taskGroup.RestartPolicy.Mode } - - + + { taskGroup.Count } + { taskGroup.Tasks.length } + + { taskGroup.RestartPolicy.Mode } + + + + ) }) diff --git a/frontend/src/components/Table/Table.js b/frontend/src/components/Table/Table.js new file mode 100644 index 00000000..db4b338c --- /dev/null +++ b/frontend/src/components/Table/Table.js @@ -0,0 +1,27 @@ +import { Table as MaterialTable } from 'material-ui/Table' + +class Table extends MaterialTable { + + static defaultProps = { + allRowsSelected: false, + fixedFooter: false, + fixedHeader: false, + multiSelectable: false, + selectable: false, + + height: 'inherit', + + wrapperStyle: { + overflow: 'display' + }, + + bodyStyle: { + tableLayout: 'auto', + overflowX: 'inherit', + overflowY: 'inherit' + } + } + +} + +export default Table diff --git a/frontend/src/components/Table/TableBody.js b/frontend/src/components/Table/TableBody.js new file mode 100644 index 00000000..1a948758 --- /dev/null +++ b/frontend/src/components/Table/TableBody.js @@ -0,0 +1,13 @@ +import { TableBody as MaterialTableBody } from 'material-ui/Table' + +class TableBody extends MaterialTableBody { + + static defaultProps = { + showRowHover: true, + preScanRows: false, + displayRowCheckbox: false + } + +} + +export default TableBody diff --git a/frontend/src/components/Table/TableFooter.js b/frontend/src/components/Table/TableFooter.js new file mode 100644 index 00000000..abfabd4d --- /dev/null +++ b/frontend/src/components/Table/TableFooter.js @@ -0,0 +1,7 @@ +import { TableFooter as MaterialTableFooter } from 'material-ui/Table' + +class TableFooter extends MaterialTableFooter { + +} + +export default TableFooter diff --git a/frontend/src/components/Table/TableHeader.js b/frontend/src/components/Table/TableHeader.js new file mode 100644 index 00000000..9b91b278 --- /dev/null +++ b/frontend/src/components/Table/TableHeader.js @@ -0,0 +1,14 @@ +import { TableHeader as MaterialTableHeader } from 'material-ui/Table' + +class TableHeader extends MaterialTableHeader { + + static defaultProps = { + adjustForCheckbox: false, + displaySelectAll: false, + enableSelectAll: false, + selectAllSelected: false, + } + +} + +export default TableHeader diff --git a/frontend/src/components/Table/TableHeaderColumn.js b/frontend/src/components/Table/TableHeaderColumn.js new file mode 100644 index 00000000..6cc7499a --- /dev/null +++ b/frontend/src/components/Table/TableHeaderColumn.js @@ -0,0 +1,26 @@ +import React, { Component, PropTypes } from 'react' +import { TableHeaderColumn as MaterialTableHeaderColumn } from 'material-ui/Table' + +class TableHeaderColumn extends Component { + + static propTypes = { + style: PropTypes.object, + } + + render () { + const overrideStyle = { + paddingLeft: 0, + height: 30 + } + + const newStyle = Object.assign({}, this.props.style, overrideStyle) + const newProps = Object.assign({}, this.props) + newProps.style = newStyle; + + return () + } + +} + +export default TableHeaderColumn + diff --git a/frontend/src/components/Table/TableRow.js b/frontend/src/components/Table/TableRow.js new file mode 100644 index 00000000..ccdddf85 --- /dev/null +++ b/frontend/src/components/Table/TableRow.js @@ -0,0 +1,13 @@ +import { TableRow as MaterialTableRow } from 'material-ui/Table' + +class TableRow extends MaterialTableRow { + + static defaultProps = { + style: { + height: 0 + } + } + +} + +export default TableRow diff --git a/frontend/src/components/Table/TableRowColumn.js b/frontend/src/components/Table/TableRowColumn.js new file mode 100644 index 00000000..dd21e107 --- /dev/null +++ b/frontend/src/components/Table/TableRowColumn.js @@ -0,0 +1,19 @@ +import React, { Component } from 'react' +import { TableRowColumn as MaterialTableRowColumn } from 'material-ui/Table' + +class TableRowColumn extends Component { + + render () { + const overrideProps = { + style: { + height: 30, + paddingLeft: 0 + } + } + + return () + } + +} + +export default TableRowColumn diff --git a/frontend/src/components/Table/index.js b/frontend/src/components/Table/index.js new file mode 100644 index 00000000..1a3530ad --- /dev/null +++ b/frontend/src/components/Table/index.js @@ -0,0 +1,7 @@ +export { default as Table } from './Table' +export { default as TableBody } from './TableBody' +export { default as TableFooter } from './TableFooter' +export { default as TableHeader } from './TableHeader' +export { default as TableHeaderColumn } from './TableHeaderColumn' +export { default as TableRow } from './TableRow' +export { default as TableRowColumn } from './TableRowColumn' diff --git a/frontend/src/components/TableHelper/TableHelper.js b/frontend/src/components/TableHelper/TableHelper.js index 8f688852..d3d9c6ea 100644 --- a/frontend/src/components/TableHelper/TableHelper.js +++ b/frontend/src/components/TableHelper/TableHelper.js @@ -1,23 +1,21 @@ import React, { PropTypes } from 'react' -import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow } from 'material-ui/Table' +import { Table, TableHeader, TableRow, TableHeaderColumn, TableBody } from '../Table' -const TableHelper = ({ classes, headers, body }) => - - +const TableHelper = ({ headers, body }) => +
    + - { headers.map(header => { header }) } + { headers.map(header => + { header }) + } - + { body }
    TableHelper.propTypes = { - classes: PropTypes.string.isRequired, headers: PropTypes.array.isRequired, body: PropTypes.array.isRequired } diff --git a/frontend/src/containers/jobs.js b/frontend/src/containers/jobs.js index 472e874b..66cfac3d 100644 --- a/frontend/src/containers/jobs.js +++ b/frontend/src/containers/jobs.js @@ -3,7 +3,8 @@ import { connect } from 'react-redux' import { Link } from 'react-router' import SelectField from 'material-ui/SelectField' import MenuItem from 'material-ui/MenuItem' -import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table' +import { Card, CardHeader, CardText } from 'material-ui/Card' +import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from '../components/Table' import JobLink from '../components/JobLink/JobLink' @@ -157,42 +158,46 @@ class Jobs extends Component { return (
    -
    - {this.jobStatusFilter()} -   - {this.jobTypeFilter()} -
    - - - - - ID - Status - Type - Priority - Task Groups - { getJobStatisticsHeader() } - - - - { this.filteredJobs().map((job) => { - return ( - - - { job.Status } - { job.Type } - { job.Priority } - { this.taskGroupCount(job) } - { getJobStatisticsRow(job) } + + + + {this.jobStatusFilter()} +   + {this.jobTypeFilter()} + + + + + +
    + + + ID + Status + Type + Priority + Task Groups + { getJobStatisticsHeader() } - ) - }) - } - -
    + + + { this.filteredJobs().map((job) => { + return ( + + + { job.Status } + { job.Type } + { job.Priority } + { this.taskGroupCount(job) } + { getJobStatisticsRow(job) } + + ) + }) + } + + + +
    ) } From 062e9d5b20d88a4e22bf24f34b313fcb56fe8f7a Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Wed, 7 Dec 2016 11:47:19 +0100 Subject: [PATCH 27/45] refactor filtering of jobs --- .../JobStatusFilter/JobStatusFilter.js | 36 +++++++++ .../components/JobTypeFilter/JobTypeFilter.js | 36 +++++++++ frontend/src/containers/jobs.js | 78 +++---------------- 3 files changed, 84 insertions(+), 66 deletions(-) create mode 100644 frontend/src/components/JobStatusFilter/JobStatusFilter.js create mode 100644 frontend/src/components/JobTypeFilter/JobTypeFilter.js diff --git a/frontend/src/components/JobStatusFilter/JobStatusFilter.js b/frontend/src/components/JobStatusFilter/JobStatusFilter.js new file mode 100644 index 00000000..ebf7ad3e --- /dev/null +++ b/frontend/src/components/JobStatusFilter/JobStatusFilter.js @@ -0,0 +1,36 @@ +import React, { PropTypes } from 'react' +import { Link, withRouter } from 'react-router' +import SelectField from 'material-ui/SelectField' +import MenuItem from 'material-ui/MenuItem' + +const JobStatusFilter = ({ location }) => { + const query = location.query || {} + + let title = 'Job Status' + if ('job_status' in query) { + title = { title }: { query.job_status } + } + + return ( + + + - Any - + + + Running + + + Pending + + + Dead + + + ) +}; + +JobStatusFilter.propTypes = { + location: PropTypes.object.isRequired +}; + +export default withRouter(JobStatusFilter) diff --git a/frontend/src/components/JobTypeFilter/JobTypeFilter.js b/frontend/src/components/JobTypeFilter/JobTypeFilter.js new file mode 100644 index 00000000..2ba141cf --- /dev/null +++ b/frontend/src/components/JobTypeFilter/JobTypeFilter.js @@ -0,0 +1,36 @@ +import React, { PropTypes } from 'react' +import { Link, withRouter } from 'react-router' +import SelectField from 'material-ui/SelectField' +import MenuItem from 'material-ui/MenuItem' + +const JobTypeFilter = ({ location }) => { + const query = location.query || {} + + let title = 'Job Type' + if ('job_type' in query) { + title = { title }: { query.job_type } + } + + return ( + + + - Any - + + + System + + + Batch + + + Service + + + ) +}; + +JobTypeFilter.propTypes = { + location: PropTypes.object.isRequired +}; + +export default withRouter(JobTypeFilter) diff --git a/frontend/src/containers/jobs.js b/frontend/src/containers/jobs.js index 66cfac3d..be4caa90 100644 --- a/frontend/src/containers/jobs.js +++ b/frontend/src/containers/jobs.js @@ -1,11 +1,9 @@ import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' -import { Link } from 'react-router' -import SelectField from 'material-ui/SelectField' -import MenuItem from 'material-ui/MenuItem' import { Card, CardHeader, CardText } from 'material-ui/Card' import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from '../components/Table' - +import JobStatusFilter from '../components/JobStatusFilter/JobStatusFilter' +import JobTypeFilter from '../components/JobTypeFilter/JobTypeFilter' import JobLink from '../components/JobLink/JobLink' const columnFormat = { @@ -29,12 +27,10 @@ const getJobStatisticsHeader = () => { summaryLabels.forEach((key) => { output.push( - + { key } - ) + + ) }) return output @@ -66,7 +62,11 @@ const getJobStatisticsRow = (job) => { const output = [] summaryLabels.forEach((key) => { - output.push({counter[key]}) + output.push( + + {counter[key]} + + ) }) return output @@ -89,60 +89,6 @@ class Jobs extends Component { return jobs } - jobTypeFilter () { - const location = this.props.location - const query = this.props.location.query || {} - - let title = 'Job Type' - if ('job_type' in query) { - title = { title }: { query.job_type } - } - - return ( - - - - Any - - - - System - - - Batch - - - Service - - - ) - } - - jobStatusFilter () { - const location = this.props.location - const query = this.props.location.query || {} - - let title = 'Job Status' - if ('job_status' in query) { - title = { title }: { query.job_status } - } - - return ( - - - - Any - - - - Running - - - Pending - - - Dead - - - ) - } - taskGroupCount (job) { let taskGroupCount = 'N/A' @@ -161,9 +107,9 @@ class Jobs extends Component { - {this.jobStatusFilter()} +   - {this.jobTypeFilter()} + From e7364789e14d3d67c3dfee36cfb2332bb9da0522 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Wed, 7 Dec 2016 12:02:08 +0100 Subject: [PATCH 28/45] make a few components into functional views --- .../AllocationLink/AllocationLink.js | 25 +++++---- .../src/components/FormatTime/FormatTime.js | 51 +++++++++---------- frontend/src/components/JobLink/JobLink.js | 42 +++++++-------- 3 files changed, 55 insertions(+), 63 deletions(-) diff --git a/frontend/src/components/AllocationLink/AllocationLink.js b/frontend/src/components/AllocationLink/AllocationLink.js index 6ce22e29..57ec82ae 100644 --- a/frontend/src/components/AllocationLink/AllocationLink.js +++ b/frontend/src/components/AllocationLink/AllocationLink.js @@ -1,20 +1,19 @@ -import React, { PureComponent, PropTypes } from 'react' +import React, { PropTypes } from 'react' import { Link } from 'react-router' -import shortUUID from '../../helpers/uuid' +import { default as shortenUUID } from '../../helpers/uuid' -class AllocationLink extends PureComponent { +const AllocationLink = ({ children, allocationId, linkAppend, shortUUID }) => { + let innerChildren = children; - render () { - const linkAppend = this.props.linkAppend - const allocationId = this.props.allocationId - let children = this.props.children - - if (children === undefined) { - children = this.props.shortUUID ? shortUUID(allocationId) : allocationId - } - - return { children } + if (children === undefined) { + innerChildren = shortUUID ? shortenUUID(allocationId) : allocationId } + + return ( + + { innerChildren } + + ) } AllocationLink.defaultProps = { diff --git a/frontend/src/components/FormatTime/FormatTime.js b/frontend/src/components/FormatTime/FormatTime.js index 08add5d1..ffb8d6ea 100644 --- a/frontend/src/components/FormatTime/FormatTime.js +++ b/frontend/src/components/FormatTime/FormatTime.js @@ -1,45 +1,42 @@ -import React, { PureComponent, PropTypes } from 'react' +import React, { PropTypes } from 'react' import ReactTooltip from 'react-tooltip' // eslint-disable-next-line no-unused-vars import momentDurationFormat from 'moment-duration-format' import moment from 'moment' import getMoment from '../../helpers/time' -class FormatTime extends PureComponent { +const FormatTime = ({ time, now, identifier, display, timeFormat, durationInterval, durationFormat }) => { + const _time = getMoment(time) + const _now = getMoment(now) - getTimeDiff (time, now) { - if (this.props.durationInterval && this.props.durationFormat) { - return moment - .duration(time.diff(now), this.props.durationInterval) - .format(this.props.durationFormat, { forceLength: true }) - } + let timeDiff = undefined; - return time.from(now, true) + if (durationInterval && durationFormat) { + timeDiff = moment + .duration(_time.diff(_now), durationInterval) + .format(durationFormat, { forceLength: true }) + } else { + timeDiff = _time.from(_now, true) } - render () { - const time = getMoment(this.props.time) - const now = getMoment(this.props.now) - const format = this.props.timeFormat - - if (this.props.display === 'relative') { - return ( - - { time.format(format) } - - {this.getTimeDiff(time, now)} - - - ) - } - + if (display === 'relative') { return ( - { this.getTimeDiff(time, now) } - { time.format(format) } + { _time.format(timeFormat) } + + { timeDiff } + ) } + + return ( + + { timeDiff } + { _time.format(timeFormat) } + + ) + } FormatTime.defaultProps = { diff --git a/frontend/src/components/JobLink/JobLink.js b/frontend/src/components/JobLink/JobLink.js index 216d6fa6..ef61d7fe 100644 --- a/frontend/src/components/JobLink/JobLink.js +++ b/frontend/src/components/JobLink/JobLink.js @@ -1,35 +1,31 @@ -import React, { PureComponent, PropTypes } from 'react' +import React, { PropTypes } from 'react' import { Link } from 'react-router' -class JobLink extends PureComponent { +const JobLink = ({ children, jobId, linkAppend, taskGroupId, taskId }) => { - render () { - const jobId = this.props.jobId - const JobIdUrl = encodeURIComponent(jobId) - const taskId = this.props.taskId - const taskGroupId = this.props.taskGroupId + const JobIdUrl = encodeURIComponent(jobId) - let linkAppend = this.props.linkAppend - let children = this.props.children - - if (taskId) { - if (!taskGroupId) { - throw new Error('Cant link to a job taskId without a taskGroupId') - } - - linkAppend = linkAppend + '/tasks' + if (taskId) { + if (!taskGroupId) { + throw new Error('Cant link to a job taskId without a taskGroupId') } - if (taskGroupId) { - linkAppend = linkAppend + '/taskGroups' - } + linkAppend = linkAppend + '/tasks' + } - if (children === undefined) { - children = jobId - } + if (taskGroupId) { + linkAppend = linkAppend + '/taskGroups' + } - return { children } + if (children === undefined) { + children = jobId } + + return ( + + { children } + + ) } JobLink.defaultProps = { From 2d82a52c4e39c334404b82da3f84228537c43015 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Wed, 7 Dec 2016 17:10:14 +0100 Subject: [PATCH 29/45] only subscribe to WS events that the container really need --- backend/actions.go | 44 ++++-- backend/connection.go | 149 ++++++++++++++---- backend/hub.go | 5 +- backend/nomad.go | 20 +-- .../AllocationFiles/AllocationFiles.js | 4 + frontend/src/containers/allocations.js | 18 ++- frontend/src/containers/clients.js | 88 ++++++----- frontend/src/containers/evaluations.js | 38 +++-- frontend/src/containers/jobs.js | 12 +- frontend/src/containers/servers.js | 109 +++++++------ frontend/src/sagas/event.js | 49 +++++- 11 files changed, 373 insertions(+), 163 deletions(-) diff --git a/backend/actions.go b/backend/actions.go index 64db9b99..9b120d46 100644 --- a/backend/actions.go +++ b/backend/actions.go @@ -1,32 +1,47 @@ package main const ( + watchAllocs = "WATCH_ALLOCS" + unwatchAllocs = "UNWATCH_ALLOCS" fetchedAllocs = "FETCHED_ALLOCS" - fetchedAlloc = "FETCHED_ALLOC" - watchAlloc = "WATCH_ALLOC" - unwatchAlloc = "UNWATCH_ALLOC" + fetchedAlloc = "FETCHED_ALLOC" + watchAlloc = "WATCH_ALLOC" + unwatchAlloc = "UNWATCH_ALLOC" + + watchEvals = "WATCH_EVALS" + unwatchEvals = "UNWATCH_EVALS" fetchedEvals = "FETCHED_EVALS" + fetchedEval = "FETCHED_EVAL" watchEval = "WATCH_EVAL" unwatchEval = "UNWATCH_EVAL" + watchJobs = "WATCH_JOBS" + unwatchJobs = "UNWATCH_JOBS" fetchedJobs = "FETCHED_JOBS" - fetchedJob = "FETCHED_JOB" - watchJob = "WATCH_JOB" - unwatchJob = "UNWATCH_JOB" + fetchedJob = "FETCHED_JOB" + watchJob = "WATCH_JOB" + unwatchJob = "UNWATCH_JOB" + + watchNodes = "WATCH_NODES" + unwatchNodes = "UNWATCH_NODES" fetchedNodes = "FETCHED_NODES" - fetchedNode = "FETCHED_NODE" - fetchNode = "FETCH_NODE" - watchNode = "WATCH_NODE" - unwatchNode = "UNWATCH_NODE" + fetchedNode = "FETCHED_NODE" + fetchNode = "FETCH_NODE" + watchNode = "WATCH_NODE" + unwatchNode = "UNWATCH_NODE" + + watchMembers = "WATCH_MEMBERS" + unwatchMembers = "UNWATCH_MEMBERS" fetchedMembers = "FETCHED_MEMBERS" - fetchedMember = "FETCHED_MEMBER" - fetchMember = "FETCH_MEMBER" - watchMember = "WATCH_MEMBER" - unwatchMember = "UNWATCH_MEMBER" + + fetchedMember = "FETCHED_MEMBER" + fetchMember = "FETCH_MEMBER" + watchMember = "WATCH_MEMBER" + unwatchMember = "UNWATCH_MEMBER" fetchDir = "FETCH_DIR" fetchedDir = "FETCHED_DIR" @@ -41,5 +56,6 @@ const ( // via a websocket connection. type Action struct { Type string + Index uint64 Payload interface{} } diff --git a/backend/connection.go b/backend/connection.go index f16cf438..aa2b74c9 100644 --- a/backend/connection.go +++ b/backend/connection.go @@ -82,9 +82,6 @@ func (c *Connection) readPump() { // Register this connection with the hub for broadcast updates c.hub.register <- c - // Flush all current state to the websocket - c.hub.nomad.FlushAll(c) - var action Action for { err := c.socket.ReadJSON(&action) @@ -96,36 +93,95 @@ func (c *Connection) readPump() { } func (c *Connection) process(action Action) { + logger.Infof("Processing event %s (index %d)", action.Type, action.Index) + switch action.Type { - case fetchMember: - c.fetchMember(action) + // + // Actions for a list of members (aka servers in the UI) + // + case watchMembers: + go c.watchGenericBroadcast("members", fetchedMembers, c.hub.nomad.members) + case unwatchMembers: + c.unwatchGenericBroadcast("members") + + // + // Actions for a list of jobs + // + case watchJobs: + go c.watchGenericBroadcast("jobs", fetchedJobs, c.hub.nomad.jobs) + case unwatchJobs: + c.unwatchGenericBroadcast("jobs") + + // + // Actions for a list of allocations + // + case watchAllocs: + go c.watchGenericBroadcast("allocs", fetchedAllocs, c.hub.nomad.allocs) + case unwatchAllocs: + c.unwatchGenericBroadcast("allocs") + + // + // Actions for a list of nodes (aka clients in the UI) + // + case watchNodes: + go c.watchGenericBroadcast("nodes", fetchedNodes, c.hub.nomad.nodes) + case unwatchNodes: + c.unwatchGenericBroadcast("nodes") + + // + // Actions for a list of evaluations + // + case watchEvals: + go c.watchGenericBroadcast("evaluations", fetchedEvals, c.hub.nomad.evals) + case unwatchEvals: + c.unwatchGenericBroadcast("evaluations") + + // + // Actions for a single node (aka client in the UI) + // + case watchNode: + go c.watchNode(action) + case unwatchNode: + c.watches.Remove(action.Payload.(string)) case fetchNode: - c.fetchNode(action) - case fetchDir: - c.fetchDir(action) + go c.fetchNode(action) + + // + // Actions for a single job + // case watchJob: go c.watchJob(action) + case unwatchJob: + c.watches.Remove(action.Payload.(string)) + + // + // Actions for a single allocation + // case watchAlloc: go c.watchAlloc(action) - case watchEval: - go c.watchEval(action) + case unwatchAlloc: + c.watches.Remove(action.Payload.(string)) + case fetchDir: // for file browsing in an allocation + go c.fetchDir(action) + case watchFile: // for following (tail -f) a file in an allocation + go c.watchFile(action) + case unwatchFile: // for stopping a follow of a file (tail -f) + c.watches.Remove(action.Payload.(string)) + + // + // Actions for a single member (aka server in the UI) + // case watchMember: go c.watchMember(action) - case watchNode: - go c.watchNode(action) - case watchFile: - go c.watchFile(action) - case unwatchEval: - fallthrough case unwatchMember: - fallthrough - case unwatchNode: - fallthrough - case unwatchJob: - fallthrough - case unwatchAlloc: c.watches.Remove(action.Payload.(string)) - case unwatchFile: + case fetchMember: + go c.fetchMember(action) + + // Actions for a single evaluation + case watchEval: + go c.watchEval(action) + case unwatchEval: c.watches.Remove(action.Payload.(string)) } } @@ -166,7 +222,7 @@ func (c *Connection) watchAlloc(action Action) { if !c.watches.Has(allocID) { return } - c.send <- &Action{Type: fetchedAlloc, Payload: alloc} + c.send <- &Action{Type: fetchedAlloc, Payload: alloc, Index: meta.LastIndex} waitIndex := meta.LastIndex if q.WaitIndex > meta.LastIndex { @@ -203,7 +259,7 @@ func (c *Connection) watchEval(action Action) { if !c.watches.Has(evalID) { return } - c.send <- &Action{Type: fetchedEval, Payload: eval} + c.send <- &Action{Type: fetchedEval, Payload: eval, Index: meta.LastIndex} waitIndex := meta.LastIndex if q.WaitIndex > meta.LastIndex { @@ -292,7 +348,7 @@ func (c *Connection) watchNode(action Action) { if !c.watches.Has(nodeID) { return } - c.send <- &Action{Type: fetchedNode, Payload: node} + c.send <- &Action{Type: fetchedNode, Payload: node, Index: meta.LastIndex} waitIndex := meta.LastIndex if q.WaitIndex > meta.LastIndex { @@ -303,6 +359,40 @@ func (c *Connection) watchNode(action Action) { } } +func (c *Connection) watchGenericBroadcast(watchKey string, actionEvent string, initialPayload interface{}) { + defer func() { + c.watches.Remove(watchKey) + logger.Infof("Stopped watching %s", watchKey) + }() + c.watches.Add(watchKey) + + logger.Infof("Sending our current %s list", watchKey) + c.send <- &Action{Type: actionEvent, Payload: initialPayload, Index: 0} + + logger.Infof("Started watching %s", watchKey) + for { + if !c.watches.Has(watchKey) { + logger.Infof("Connection is no longer subscribed to %s", watchKey) + return + } + + logger.Infof("Waiting on %s pipe", watchKey) + channelAction := <-c.hub.nomad.updateCh + + if channelAction.Type != actionEvent { + logger.Infof("Type mismatch: %s <> %s", channelAction.Type, actionEvent) + continue + } + + c.send <- channelAction + } +} + +func (c *Connection) unwatchGenericBroadcast(watchKey string) { + logger.Infof("Removing subscription for %s", watchKey) + c.watches.Remove(watchKey) +} + func (c *Connection) watchJob(action Action) { jobID := action.Payload.(string) @@ -329,7 +419,7 @@ func (c *Connection) watchJob(action Action) { if !c.watches.Has(jobID) { return } - c.send <- &Action{Type: fetchedJob, Payload: job} + c.send <- &Action{Type: fetchedJob, Payload: job, Index: meta.LastIndex} waitIndex := meta.LastIndex if q.WaitIndex > meta.LastIndex { @@ -368,7 +458,7 @@ func (c *Connection) fetchDir(action Action) { logger.Errorf("Unable to fetch directory: %s", err) } - c.send <- &Action{Type: fetchedDir, Payload: dir} + c.send <- &Action{Type: fetchedDir, Payload: dir, Index: 0} } type Line struct { @@ -426,6 +516,7 @@ func (c *Connection) watchFile(action Action) { }{ path: path, }, + Index: 0, } logger.Errorf("Unable to stream file: %s", err) @@ -471,6 +562,7 @@ func (c *Connection) watchFile(action Action) { Data: "", Oversized: oversized, }, + Index: 0, } ticker := time.NewTicker(10 * time.Second) @@ -493,6 +585,7 @@ func (c *Connection) watchFile(action Action) { Data: string(line), Oversized: oversized, }, + Index: 0, } case <-ticker.C: if !c.watches.Has(path) { diff --git a/backend/hub.go b/backend/hub.go index b9a34a11..33378b7c 100644 --- a/backend/hub.go +++ b/backend/hub.go @@ -39,16 +39,19 @@ func NewHub(nomad *Nomad, broadcast chan *Action) *Hub { func (h *Hub) Run() { for { select { + case c := <-h.register: h.connections[c] = true + case c := <-h.unregister: if _, ok := h.connections[c]; ok { delete(h.connections, c) close(c.send) } + case action := <-h.broadcast: for c := range h.connections { - c.send <- action + c.process(*action) } } } diff --git a/backend/nomad.go b/backend/nomad.go index 73ec7994..cf80ad1b 100644 --- a/backend/nomad.go +++ b/backend/nomad.go @@ -97,16 +97,6 @@ func NewNomad(url string, updateCh chan *Action) (*Nomad, error) { }, nil } -// FlushAll sends the current Nomad state to the connection. This is used to pass -// all known state to the client connection. -func (n *Nomad) FlushAll(c *Connection) { - c.send <- &Action{Type: fetchedAllocs, Payload: n.allocs} - c.send <- &Action{Type: fetchedEvals, Payload: n.evals} - c.send <- &Action{Type: fetchedJobs, Payload: n.jobs} - c.send <- &Action{Type: fetchedNodes, Payload: n.nodes} - c.send <- &Action{Type: fetchedMembers, Payload: n.members} -} - // MembersWithID is used to query all of the known server members. func (n *Nomad) MembersWithID() ([]*AgentMemberWithID, error) { members, err := n.Client.Agent().Members() @@ -170,7 +160,7 @@ func (n *Nomad) watchAllocs() { continue } n.allocs = allocs - n.updateCh <- &Action{Type: fetchedAllocs, Payload: allocs} + n.updateCh <- &Action{Type: fetchedAllocs, Payload: allocs, Index: meta.LastIndex} // Guard for zero LastIndex in case of timeout waitIndex := meta.LastIndex @@ -191,7 +181,7 @@ func (n *Nomad) watchEvals() { continue } n.evals = evals - n.updateCh <- &Action{Type: fetchedEvals, Payload: evals} + n.updateCh <- &Action{Type: fetchedEvals, Payload: evals, Index: meta.LastIndex} // Guard for zero LastIndex in case of timeout waitIndex := meta.LastIndex @@ -212,7 +202,7 @@ func (n *Nomad) watchJobs() { continue } n.jobs = jobs - n.updateCh <- &Action{Type: fetchedJobs, Payload: jobs} + n.updateCh <- &Action{Type: fetchedJobs, Payload: jobs, Index: meta.LastIndex} // Guard for zero LastIndex in case of timeout waitIndex := meta.LastIndex @@ -233,7 +223,7 @@ func (n *Nomad) watchNodes() { continue } n.nodes = nodes - n.updateCh <- &Action{Type: fetchedNodes, Payload: nodes} + n.updateCh <- &Action{Type: fetchedNodes, Payload: nodes, Index: meta.LastIndex} // Guard for zero LastIndex in case of timeout waitIndex := meta.LastIndex @@ -254,7 +244,7 @@ func (n *Nomad) watchMembers() { } n.members = members - n.updateCh <- &Action{Type: fetchedMembers, Payload: members} + n.updateCh <- &Action{Type: fetchedMembers, Payload: members, Index: 0} time.Sleep(10 * time.Second) } diff --git a/frontend/src/components/AllocationFiles/AllocationFiles.js b/frontend/src/components/AllocationFiles/AllocationFiles.js index cf085087..8ff2017c 100644 --- a/frontend/src/components/AllocationFiles/AllocationFiles.js +++ b/frontend/src/components/AllocationFiles/AllocationFiles.js @@ -237,6 +237,10 @@ class AllocationFiles extends Component { } collectFiles () { + if (!this.props.directory || this.props.directory.length === 0) { + return []; + } + const files = this.props.directory.map((file) => { const a = file.IsDir ? '/' : '' const b = file.Name + a diff --git a/frontend/src/containers/allocations.js b/frontend/src/containers/allocations.js index e4bad40a..acb4ce97 100644 --- a/frontend/src/containers/allocations.js +++ b/frontend/src/containers/allocations.js @@ -1,8 +1,19 @@ -import React, { PureComponent, PropTypes } from 'react' +import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' import AllocationList from '../components/AllocationList/AllocationList' +import { WATCH_ALLOCS, UNWATCH_ALLOCS, WATCH_NODES, UNWATCH_NODES } from '../sagas/event' -class Allocations extends PureComponent { +class Allocations extends Component { + + componentDidMount() { + this.props.dispatch({type: WATCH_ALLOCS }) + this.props.dispatch({type: WATCH_NODES }) + } + + componentWillUnmount() { + this.props.dispatch({type: UNWATCH_ALLOCS }) + this.props.dispatch({type: UNWATCH_NODES }) + } render () { return @@ -15,7 +26,8 @@ function mapStateToProps ({ allocations, nodes }) { Allocations.propTypes = { allocations: PropTypes.array.isRequired, // eslint-disable-line no-unused-vars - nodes: PropTypes.array.isRequired // eslint-disable-line no-unused-vars + nodes: PropTypes.array.isRequired, // eslint-disable-line no-unused-vars + dispatch: PropTypes.func.isRequired, } export default connect(mapStateToProps)(Allocations) diff --git a/frontend/src/containers/clients.js b/frontend/src/containers/clients.js index 778178dc..f6b2ca90 100644 --- a/frontend/src/containers/clients.js +++ b/frontend/src/containers/clients.js @@ -1,52 +1,68 @@ -import React, { PropTypes } from 'react' +import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' +import { WATCH_NODES, UNWATCH_NODES } from '../sagas/event' import ClientLink from '../components/ClientLink/ClientLink' import FormatBoolean from '../components/FormatBoolean/FormatBoolean' import NodeStatus from '../components/NodeStatus/NodeStatus' -const Clients = ({ nodes }) => -
    -
    -
    -
    -

    Clients

    -
    -
    - - - - - - - - - - - - - { nodes.map(node => - - - - - - - - - )} - -
    IDNameStatusDrainDatacenterClass
    { node.Name }{ node.Datacenter }{ node.NodeClass ? node.NodeClass : ''}
    +class Clients extends Component { + + componentDidMount() { + this.props.dispatch({ type: WATCH_NODES }) + } + + componentWillUnmount() { + this.props.dispatch({ type: UNWATCH_NODES }) + } + + render() { + return ( +
    +
    +
    +
    +

    Clients

    +
    +
    + + + + + + + + + + + + + { this.props.nodes.map(node => + + + + + + + + + )} + +
    IDNameStatusDrainDatacenterClass
    { node.Name }{ node.Datacenter }{ node.NodeClass ? node.NodeClass : ''}
    +
    +
    -
    -
    + ) + } +} function mapStateToProps ({ nodes }) { return { nodes } } Clients.propTypes = { - nodes: PropTypes.array.isRequired + nodes: PropTypes.array.isRequired, + dispatch: PropTypes.func.isRequired, } export default connect(mapStateToProps)(Clients) diff --git a/frontend/src/containers/evaluations.js b/frontend/src/containers/evaluations.js index 2e6d43a5..94548eb1 100644 --- a/frontend/src/containers/evaluations.js +++ b/frontend/src/containers/evaluations.js @@ -1,18 +1,33 @@ -import React, { PropTypes } from 'react' +import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' +import { WATCH_EVALS, UNWATCH_EVALS } from '../sagas/event' import EvaluationList from '../components/EvaluationList/EvaluationList' -const Evaluations = ({ evaluations }) => -
    -
    -
    -
    -

    Evaluations

    +class Evaluations extends Component { + + componentDidMount() { + this.props.dispatch({ type: WATCH_EVALS }) + } + + componentWillUnmount() { + this.props.dispatch({ type: UNWATCH_EVALS }) + } + + render() { + return ( +
    +
    +
    +
    +

    Evaluations

    +
    + +
    -
    -
    -
    + ) + } +} function mapStateToProps ({ evaluations }) { return { evaluations } @@ -23,7 +38,8 @@ Evaluations.defaultProps = { } Evaluations.propTypes = { - evaluations: PropTypes.array.isRequired + evaluations: PropTypes.array.isRequired, + dispatch: PropTypes.func.isRequired, } export default connect(mapStateToProps)(Evaluations) diff --git a/frontend/src/containers/jobs.js b/frontend/src/containers/jobs.js index be4caa90..666033a9 100644 --- a/frontend/src/containers/jobs.js +++ b/frontend/src/containers/jobs.js @@ -5,6 +5,7 @@ import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowCol import JobStatusFilter from '../components/JobStatusFilter/JobStatusFilter' import JobTypeFilter from '../components/JobTypeFilter/JobTypeFilter' import JobLink from '../components/JobLink/JobLink' +import { WATCH_JOBS, UNWATCH_JOBS } from '../sagas/event' const columnFormat = { width: 50, @@ -74,6 +75,14 @@ const getJobStatisticsRow = (job) => { class Jobs extends Component { + componentDidMount() { + this.props.dispatch({type: WATCH_JOBS}) + } + + componentWillUnmount() { + this.props.dispatch({type: UNWATCH_JOBS}) + } + filteredJobs () { const query = this.props.location.query || {} let jobs = this.props.jobs @@ -160,7 +169,8 @@ Jobs.defaultProps = { Jobs.propTypes = { jobs: PropTypes.array.isRequired, - location: PropTypes.object.isRequired + location: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired, } export default connect(mapStateToProps)(Jobs) diff --git a/frontend/src/containers/servers.js b/frontend/src/containers/servers.js index aa3690a3..8fd30561 100644 --- a/frontend/src/containers/servers.js +++ b/frontend/src/containers/servers.js @@ -1,57 +1,69 @@ -import React, { PropTypes } from 'react' +import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' +import { WATCH_MEMBERS, UNWATCH_MEMBERS } from '../sagas/event' import ServerLink from '../components/ServerLink/ServerLink' import FormatBoolean from '../components/FormatBoolean/FormatBoolean' -const Servers = ({ members }) => { - return ( -
    -
    -
    -
    -

    Servers

    -
    -
    - - - - - - - - - - - - - - - - - { members.map((member) => { - return ( - - - - - - - - - - - - - ) - }) - } - -
    IDNameAddressPortStatusLeaderProtocolBuildDatacenterRegion
    { member.Name }{ member.Addr }{ member.Port }{ member.Status }{ member.ProtocolCur }{ member.Tags.build }{ member.Tags.dc }{ member.Tags.region }
    +class Servers extends Component { + + componentDidMount() { + this.props.dispatch({ type: WATCH_MEMBERS }) + } + + componentWillUnmount() { + this.props.dispatch({ type: UNWATCH_MEMBERS }) + } + + render() { + return ( +
    +
    +
    +
    +

    Servers

    +
    +
    + + + + + + + + + + + + + + + + + { this.props.members.map((member) => { + return ( + + + + + + + + + + + + + ) + }) + } + +
    IDNameAddressPortStatusLeaderProtocolBuildDatacenterRegion
    { member.Name }{ member.Addr }{ member.Port }{ member.Status }{ member.ProtocolCur }{ member.Tags.build }{ member.Tags.dc }{ member.Tags.region }
    +
    -
    - ) + ) + } } function mapStateToProps ({ members }) { @@ -59,7 +71,8 @@ function mapStateToProps ({ members }) { } Servers.propTypes = { - members: PropTypes.array.isRequired + members: PropTypes.array.isRequired, + dispatch: PropTypes.func.isRequired, } export default connect(mapStateToProps)(Servers) diff --git a/frontend/src/sagas/event.js b/frontend/src/sagas/event.js index 041ec25e..6a4ed67b 100644 --- a/frontend/src/sagas/event.js +++ b/frontend/src/sagas/event.js @@ -1,29 +1,44 @@ import { delay, eventChannel } from 'redux-saga' import { fork, take, call, put } from 'redux-saga/effects' +export const WATCH_JOBS = 'WATCH_JOBS'; export const FETCHED_JOBS = 'FETCHED_JOBS' -export const FETCHED_JOB = 'FETCHED_JOB' +export const UNWATCH_JOBS = 'UNWATCH_JOBS' + export const WATCH_JOB = 'WATCH_JOB' +export const FETCHED_JOB = 'FETCHED_JOB' export const UNWATCH_JOB = 'UNWATCH_JOB' export const FETCHED_MEMBERS = 'FETCHED_MEMBERS' +export const WATCH_MEMBERS = 'WATCH_MEMBERS' +export const UNWATCH_MEMBERS = 'UNWATCH_MEMBERS' + export const FETCHED_MEMBER = 'FETCHED_MEMBER' export const FETCH_MEMBER = 'FETCH_MEMBER' export const WATCH_MEMBER = 'WATCH_MEMBER' export const UNWATCH_MEMBER = 'UNWATCH_MEMBER' +export const WATCH_NODES = 'WATCH_NODES'; export const FETCHED_NODES = 'FETCHED_NODES' +export const UNWATCH_NODES = 'UNWATCH_NODES'; + export const FETCHED_NODE = 'FETCHED_NODE' export const FETCH_NODE = 'FETCH_NODE' export const WATCH_NODE = 'WATCH_NODE' export const UNWATCH_NODE = 'UNWATCH_NODE' +export const WATCH_EVALS = 'WATCH_EVALS'; +export const UNWATCH_EVALS = 'UNWATCH_EVALS'; export const FETCHED_EVALS = 'FETCHED_EVALS' -export const FETCHED_EVAL = 'FETCHED_EVAL' + export const WATCH_EVAL = 'WATCH_EVAL' export const UNWATCH_EVAL = 'UNWATCH_EVAL' +export const FETCHED_EVAL = 'FETCHED_EVAL' +export const WATCH_ALLOCS = 'WATCH_ALLOCS' export const FETCHED_ALLOCS = 'FETCHED_ALLOCS' +export const UNWATCH_ALLOCS = 'UNWATCH_ALLOCS' + export const FETCHED_ALLOC = 'FETCHED_ALLOC' export const WATCH_ALLOC = 'WATCH_ALLOC' export const UNWATCH_ALLOC = 'UNWATCH_ALLOC' @@ -40,7 +55,7 @@ export const CLEAR_RECEIVED_FILE_DATA = 'CLEAR_RECEIVED_FILE_DATA' function subscribe (socket) { return eventChannel((emit) => { - // eslint-disable-next-line no-param-reassign + // eslint-disable-next-line no-param-reassign socket.onmessage = (event) => { const data = JSON.parse(event.data) emit({ @@ -63,22 +78,44 @@ function* read (socket) { function* write (socket) { while (true) { const action = yield take([ + WATCH_JOBS, + UNWATCH_JOBS, + WATCH_JOB, UNWATCH_JOB, + + WATCH_ALLOCS, + UNWATCH_ALLOCS, + WATCH_ALLOC, UNWATCH_ALLOC, + WATCH_EVAL, UNWATCH_EVAL, + + WATCH_EVALS, + UNWATCH_EVALS, + + WATCH_NODES, + UNWATCH_NODES, + WATCH_NODE, UNWATCH_NODE, FETCH_NODE, + + WATCH_MEMBERS, + UNWATCH_MEMBERS, + WATCH_MEMBER, UNWATCH_MEMBER, FETCH_MEMBER, + FETCH_DIR, + WATCH_FILE, UNWATCH_FILE ]) + socket.send(JSON.stringify(action)) } } @@ -116,9 +153,9 @@ export default function eventSaga () { return new Promise((resolve, reject) => { const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:' - // If we build production page, assume /ws run inside the go-binary - // and such on same host+port otherwise assume development, where we - // re-use the hostname but use GO_PORT end with fallback to :3000. + // If we build production page, assume /ws run inside the go-binary + // and such on same host+port otherwise assume development, where we + // re-use the hostname but use GO_PORT end with fallback to :3000. let hostname if (process.env.NODE_ENV === 'production') { hostname = location.host From aa7ceda45efebe2db80682bd86a46858d2ef7026 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Wed, 7 Dec 2016 17:20:27 +0100 Subject: [PATCH 30/45] format code --- backend/actions.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/actions.go b/backend/actions.go index 9b120d46..a4a9608a 100644 --- a/backend/actions.go +++ b/backend/actions.go @@ -13,9 +13,9 @@ const ( unwatchEvals = "UNWATCH_EVALS" fetchedEvals = "FETCHED_EVALS" - fetchedEval = "FETCHED_EVAL" - watchEval = "WATCH_EVAL" - unwatchEval = "UNWATCH_EVAL" + fetchedEval = "FETCHED_EVAL" + watchEval = "WATCH_EVAL" + unwatchEval = "UNWATCH_EVAL" watchJobs = "WATCH_JOBS" unwatchJobs = "UNWATCH_JOBS" From 7dadeaa639d0deb30b66f1ccd2627dc30b2dba7c Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Wed, 7 Dec 2016 17:46:53 +0100 Subject: [PATCH 31/45] restyling server/info server/raw and servers --- .../components/FormatBoolean/FormatBoolean.js | 15 ++-- .../src/components/ServerInfo/ServerInfo.js | 68 ++++++++------ .../src/components/ServerRaw/ServerRaw.js | 12 ++- .../ViewServerTopbar/ViewServerTopbar.js | 65 ++++++++++++++ frontend/src/containers/job.js | 43 +-------- frontend/src/containers/jobs.js | 4 +- frontend/src/containers/server.js | 58 ++++-------- frontend/src/containers/servers.js | 88 +++++++++---------- 8 files changed, 186 insertions(+), 167 deletions(-) create mode 100644 frontend/src/components/ViewServerTopbar/ViewServerTopbar.js diff --git a/frontend/src/components/FormatBoolean/FormatBoolean.js b/frontend/src/components/FormatBoolean/FormatBoolean.js index b25abab5..4b4e0a27 100644 --- a/frontend/src/components/FormatBoolean/FormatBoolean.js +++ b/frontend/src/components/FormatBoolean/FormatBoolean.js @@ -1,5 +1,6 @@ import React, { PropTypes } from 'react' -import { Glyphicon } from 'react-bootstrap' +import FontIcon from 'material-ui/FontIcon' +import { green500, red500 } from 'material-ui/styles/colors' const FormatBoolean = ({ title, @@ -12,16 +13,16 @@ const FormatBoolean = ({ falseIcon, trueIcon }) => { - let colorClass + let color let icon let text if (withColor) { - colorClass = value ? 'text-success' : 'text-danger' + color = value ? green500 : red500 } if (withIcon) { - icon = + icon = { value ? trueIcon : falseIcon } } if (withText) { @@ -29,7 +30,7 @@ const FormatBoolean = ({ } return ( - { icon } { text } + { icon } { text } ) } @@ -42,10 +43,10 @@ FormatBoolean.defaultProps = { withText: false, trueText: 'yes', - trueIcon: 'ok', + trueIcon: 'check', falseText: 'no', - falseIcon: 'remove' + falseIcon: 'close' } FormatBoolean.propTypes = { diff --git a/frontend/src/components/ServerInfo/ServerInfo.js b/frontend/src/components/ServerInfo/ServerInfo.js index 029caa52..b30032ee 100644 --- a/frontend/src/components/ServerInfo/ServerInfo.js +++ b/frontend/src/components/ServerInfo/ServerInfo.js @@ -1,16 +1,23 @@ import React, { PropTypes } from 'react' import { connect } from 'react-redux' +import { Grid, Row, Col } from 'react-flexbox-grid' +import { Card, CardTitle, CardText } from 'material-ui/Card' +import { TableRow, TableRowColumn } from '../Table' import TableHelper from '../TableHelper/TableHelper' const memberProps = [ 'ID', 'Name', - 'Address', + 'Addr', 'Port', - 'Status' + 'Status', ] const ServerInfo = ({ member }) => { + if (!member) { + return 'Loading ...'; + } + const tags = member.Tags const memberTags = Object.keys(tags).map((key) => { @@ -18,33 +25,44 @@ const ServerInfo = ({ member }) => { const value = tags[key] return ( - - { name } - { value } - + + { name } + { value } + ) }) return ( -
    -
    - Server Properties -
    - { memberProps.map(memberProp => -
    -
    { memberProp }
    -
    { member[memberProp] }
    -
    - )} -
    -
    - Server Tags - { (memberTags.length > 0) ? - - : null - } -
    -
    + + + + + + +
    + { memberProps.map(memberProp => +
    +
    { memberProp }
    +
    { member[memberProp] }
    +
    + )} +
    +
    +
    + + + + + + { (memberTags.length > 0) + ? + : null + } + + + +
    +
    ) } diff --git a/frontend/src/components/ServerRaw/ServerRaw.js b/frontend/src/components/ServerRaw/ServerRaw.js index 84c7b885..7673abf9 100644 --- a/frontend/src/components/ServerRaw/ServerRaw.js +++ b/frontend/src/components/ServerRaw/ServerRaw.js @@ -1,12 +1,16 @@ import React, { PropTypes } from 'react' import { connect } from 'react-redux' - +import { Card, CardTitle, CardText } from 'material-ui/Card' import RawJson from '../RawJson/RawJson' const ServerRaw = ({ member }) => -
    - -
    + + + + + + + function mapStateToProps ({ member }) { return { member } diff --git a/frontend/src/components/ViewServerTopbar/ViewServerTopbar.js b/frontend/src/components/ViewServerTopbar/ViewServerTopbar.js new file mode 100644 index 00000000..bdb2c3dc --- /dev/null +++ b/frontend/src/components/ViewServerTopbar/ViewServerTopbar.js @@ -0,0 +1,65 @@ +import FontIcon from 'material-ui/FontIcon' +import React, { PureComponent, PropTypes } from 'react' +import { BottomNavigation, BottomNavigationItem } from 'material-ui/BottomNavigation' +import { withRouter } from 'react-router' + +const infoIcon = info_outline +const rawIcon = highlight + +class _ViewServerTopbar extends PureComponent { + + handleActive (tab) { + let path = location.pathname.split('/') + path.pop() + path = path.join('/') + this.props.router.push(path + '/' + tab) + } + + getActiveTab () { + const location = this.props.location + const end = location.pathname.split('/').pop() + + if (end.startsWith('info')) { + return 0 + } + + if (end.startsWith('raw')) { + return 1 + } + + return 0 + } + + getStyle () { + return { + borderBottom: '1px solid #e0e0e0', + marginBottom: 10 + } + } + + render () { + return ( + + this.handleActive('info') } + /> + this.handleActive('raw') } + /> + + ) + } +} + +_ViewServerTopbar.propTypes = { + router: PropTypes.object.isRequired, + location: PropTypes.object.isRequired +} + +const ViewServerTopbar = withRouter(_ViewServerTopbar) + +export default ViewServerTopbar diff --git a/frontend/src/containers/job.js b/frontend/src/containers/job.js index 425321ee..38ec1483 100644 --- a/frontend/src/containers/job.js +++ b/frontend/src/containers/job.js @@ -5,51 +5,12 @@ import { WATCH_JOB, UNWATCH_JOB } from '../sagas/event' class Job extends Component { - constructor (props) { - super(props) - - this.state = { - tabs: [ - { - name: 'Info', - path: 'info' - }, - { - name: 'Allocations', - path: 'allocations' - }, - { - name: 'Evaluations', - path: 'evaluations' - }, - { - name: 'Tasks Groups', - path: 'taskGroups' - }, - { - name: 'Tasks', - path: 'tasks' - }, - { - name: 'Raw', - path: 'raw' - } - ] - } - } - componentWillMount () { - this.props.dispatch({ - type: WATCH_JOB, - payload: this.props.params.jobId - }) + this.props.dispatch({ type: WATCH_JOB, payload: this.props.params.jobId }) } componentWillUnmount () { - this.props.dispatch({ - type: UNWATCH_JOB, - payload: this.props.params.jobId - }) + this.props.dispatch({ type: UNWATCH_JOB, payload: this.props.params.jobId }) } render () { diff --git a/frontend/src/containers/jobs.js b/frontend/src/containers/jobs.js index 666033a9..cc36d258 100644 --- a/frontend/src/containers/jobs.js +++ b/frontend/src/containers/jobs.js @@ -135,10 +135,10 @@ class Jobs extends Component { { getJobStatisticsHeader() } - + { this.filteredJobs().map((job) => { return ( - + { job.Status } { job.Type } diff --git a/frontend/src/containers/server.js b/frontend/src/containers/server.js index 7ebe3c56..3f172a04 100644 --- a/frontend/src/containers/server.js +++ b/frontend/src/containers/server.js @@ -1,61 +1,33 @@ import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' -import Tabs from '../components/Tabs/Tabs' +import ViewServerTopbar from '../components/ViewServerTopbar/ViewServerTopbar' import { WATCH_MEMBER, UNWATCH_MEMBER } from '../sagas/event' class Server extends Component { - constructor (props) { - super(props) - - this.state = { - tabs: [ - { - name: 'Info', - path: 'info' - }, - { - name: 'Raw', - path: 'raw' - } - ] - } - } - componentWillMount () { - this.props.dispatch({ - type: WATCH_MEMBER, - payload: this.props.params.memberId - }) + this.props.dispatch({ type: WATCH_MEMBER, payload: this.props.params.memberId }) } componentWillUnmount () { - this.props.dispatch({ - type: UNWATCH_MEMBER, - payload: this.props.params.memberId - }) + this.props.dispatch({ type: UNWATCH_MEMBER, payload: this.props.params.memberId }) } render () { - if (this.props.member == null) return (null) - - const path = this.props.location.pathname - const tabSlug = path.split('/').pop() - const basePath = path.substring(0, path.lastIndexOf('/')) + if (this.props.member == null) { + return 'Loading ...'; + } return ( -
    -
    -
    -
    -

    Server: { this.props.member.Name }

    -
    -
    - - { this.props.children } - -
    -
    +
    + + +
    +

    Server: { this.props.member.Name }

    + +
    + + { this.props.children }
    ) diff --git a/frontend/src/containers/servers.js b/frontend/src/containers/servers.js index 8fd30561..665ab95c 100644 --- a/frontend/src/containers/servers.js +++ b/frontend/src/containers/servers.js @@ -1,6 +1,8 @@ import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' +import { Card, CardHeader, CardText } from 'material-ui/Card' import { WATCH_MEMBERS, UNWATCH_MEMBERS } from '../sagas/event' +import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from '../components/Table' import ServerLink from '../components/ServerLink/ServerLink' import FormatBoolean from '../components/FormatBoolean/FormatBoolean' @@ -16,51 +18,47 @@ class Servers extends Component { render() { return ( -
    -
    -
    -
    -

    Servers

    -
    -
    - - - - - - - - - - - - - - - - - { this.props.members.map((member) => { - return ( - - - - - - - - - - - - - ) - }) - } - -
    IDNameAddressPortStatusLeaderProtocolBuildDatacenterRegion
    { member.Name }{ member.Addr }{ member.Port }{ member.Status }{ member.ProtocolCur }{ member.Tags.build }{ member.Tags.dc }{ member.Tags.region }
    -
    -
    -
    +
    + + + + + + + ID + Name + Address + Port + Status + Leader + Protocol + Build + Datacenter + Region + + + + { this.props.members.map((member) => { + return ( + + + { member.Name } + { member.Addr } + { member.Port } + { member.Status } + + { member.ProtocolCur } + { member.Tags.build } + { member.Tags.dc } + { member.Tags.region } + + ) + }) + } + +
    +
    +
    ) } From b9cef4a5054e825d7abba56cd87acce4afacd19a Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Thu, 8 Dec 2016 19:22:24 +0100 Subject: [PATCH 32/45] more styling and cleanup --- .../AllocationFiles/AllocationFiles.js | 12 +- .../AllocationList/AllocationList.js | 4 +- .../AllocationTopbar.js} | 10 +- .../Topbar.js => AppTopbar/AppTopbar.js} | 10 +- .../ClientAllocations/ClientAllocations.js | 27 ++-- .../ClientEvaluations/ClientEvaluations.js | 22 ++-- .../src/components/ClientInfo/ClientInfo.js | 124 ++++++++++++------ .../src/components/ClientRaw/ClientRaw.js | 11 +- .../components/ClientTopbar/ClientTopbar.js | 85 ++++++++++++ .../EvaluationInfo/EvaluationInfo.js | 37 +++--- .../EvaluationList/EvaluationList.js | 70 +++++----- .../components/EvaluationRaw/EvaluationRaw.js | 11 +- .../EvaluationTopbar/EvaluationTopbar.js | 75 +++++++++++ .../JobAllocations/JobAllocations.js | 18 ++- .../JobEvaluations/JobEvaluations.js | 16 ++- frontend/src/components/JobRaw/JobRaw.js | 11 +- .../components/JobTaskGroups/JobTaskGroups.js | 71 +++++----- .../JobTopbar.js} | 8 +- .../ServerTopbar.js} | 2 +- frontend/src/components/Tabs/Tabs.js | 31 ----- frontend/src/components/app.js | 4 +- frontend/src/containers/allocation.js | 4 +- frontend/src/containers/client.js | 66 +++------- frontend/src/containers/clients.js | 69 +++++----- frontend/src/containers/evaluation.js | 67 +++------- frontend/src/containers/evaluations.js | 13 +- frontend/src/containers/job.js | 4 +- frontend/src/containers/jobs.js | 2 +- frontend/src/containers/server.js | 4 +- frontend/src/containers/servers.js | 3 +- 30 files changed, 518 insertions(+), 373 deletions(-) rename frontend/src/components/{ViewAllocationTopbar/ViewAllocationTopbar.js => AllocationTopbar/AllocationTopbar.js} (87%) rename frontend/src/components/{Topbar/Topbar.js => AppTopbar/AppTopbar.js} (90%) create mode 100644 frontend/src/components/ClientTopbar/ClientTopbar.js create mode 100644 frontend/src/components/EvaluationTopbar/EvaluationTopbar.js rename frontend/src/components/{ViewJobTopbar/ViewJobTopbar.js => JobTopbar/JobTopbar.js} (92%) rename frontend/src/components/{ViewServerTopbar/ViewServerTopbar.js => ServerTopbar/ServerTopbar.js} (95%) delete mode 100644 frontend/src/components/Tabs/Tabs.js diff --git a/frontend/src/components/AllocationFiles/AllocationFiles.js b/frontend/src/components/AllocationFiles/AllocationFiles.js index 8ff2017c..3828f183 100644 --- a/frontend/src/components/AllocationFiles/AllocationFiles.js +++ b/frontend/src/components/AllocationFiles/AllocationFiles.js @@ -13,7 +13,9 @@ import { CLEAR_RECEIVED_FILE_DATA, CLEAR_FILE_PATH, UNWATCH_FILE, - WATCH_FILE + WATCH_FILE, + WATCH_NODES, + UNWATCH_NODES } from '../../sagas/event' class AllocationFiles extends Component { @@ -100,15 +102,15 @@ class AllocationFiles extends Component { componentDidMount () { window.addEventListener('resize', () => this.updateDimensions()) + this.props.dispatch({ type: WATCH_NODES }) this.updateDimensions() } componentWillUnmount () { window.removeEventListener('resize', () => this.updateDimensions()) - this.props.dispatch({ - type: CLEAR_FILE_PATH - }) + this.props.dispatch({ type: UNWATCH_NODES }) + this.props.dispatch({ type: CLEAR_FILE_PATH }) if (!this.state.fileWatching) { return @@ -353,7 +355,7 @@ AllocationFiles.propTypes = { file: PropTypes.object.isRequired, directory: PropTypes.array.isRequired, history: PropTypes.object.isRequired, - router: PropTypes.object.isRequired + router: PropTypes.object.isRequired, } export default connect(mapStateToProps)(AllocationFiles) diff --git a/frontend/src/components/AllocationList/AllocationList.js b/frontend/src/components/AllocationList/AllocationList.js index ab59a00e..d02ea8c5 100644 --- a/frontend/src/components/AllocationList/AllocationList.js +++ b/frontend/src/components/AllocationList/AllocationList.js @@ -171,13 +171,13 @@ class AllocationList extends PureComponent { return (
    - + { this.clientFilter() }   { this.clientStatusFilter() }   - { this.jobIdFilter() } + { showJobColumn ? this.jobIdFilter() : null } diff --git a/frontend/src/components/ViewAllocationTopbar/ViewAllocationTopbar.js b/frontend/src/components/AllocationTopbar/AllocationTopbar.js similarity index 87% rename from frontend/src/components/ViewAllocationTopbar/ViewAllocationTopbar.js rename to frontend/src/components/AllocationTopbar/AllocationTopbar.js index e946a84d..91675511 100644 --- a/frontend/src/components/ViewAllocationTopbar/ViewAllocationTopbar.js +++ b/frontend/src/components/AllocationTopbar/AllocationTopbar.js @@ -6,9 +6,9 @@ import { withRouter } from 'react-router' const infoIcon = info_outline const filesIcon = storage const logsIcon = subject -const rawIcon = highlight +const rawIcon = code -class _ViewAllocationTopbar extends PureComponent { +class _AllocationTopbar extends PureComponent { handleActive (tab) { let path = location.pathname.split('/') @@ -59,11 +59,11 @@ class _ViewAllocationTopbar extends PureComponent { } } -_ViewAllocationTopbar.propTypes = { +_AllocationTopbar.propTypes = { router: PropTypes.object.isRequired, location: PropTypes.object.isRequired } -const ViewAllocationTopbar = withRouter(_ViewAllocationTopbar) +const AllocationTopbar = withRouter(_AllocationTopbar) -export default ViewAllocationTopbar +export default AllocationTopbar diff --git a/frontend/src/components/Topbar/Topbar.js b/frontend/src/components/AppTopbar/AppTopbar.js similarity index 90% rename from frontend/src/components/Topbar/Topbar.js rename to frontend/src/components/AppTopbar/AppTopbar.js index aeb52aef..bf51a627 100644 --- a/frontend/src/components/Topbar/Topbar.js +++ b/frontend/src/components/AppTopbar/AppTopbar.js @@ -1,9 +1,9 @@ import React, { PureComponent, PropTypes } from 'react' import AppBar from 'material-ui/AppBar' import { withRouter } from 'react-router' -import {Tabs, Tab} from 'material-ui/Tabs' +import { Tabs, Tab } from 'material-ui/Tabs' -class Topbar extends PureComponent { +class AppTopbar extends PureComponent { constructor () { super() @@ -61,11 +61,11 @@ class Topbar extends PureComponent { } } -Topbar.propTypes = { +AppTopbar.propTypes = { router: PropTypes.object.isRequired, location: PropTypes.object.isRequired } -const TopbarWithRouter = withRouter(Topbar) +const AppTopbarWithRouter = withRouter(AppTopbar) -export default TopbarWithRouter +export default AppTopbarWithRouter diff --git a/frontend/src/components/ClientAllocations/ClientAllocations.js b/frontend/src/components/ClientAllocations/ClientAllocations.js index cfa198db..4b556ca8 100644 --- a/frontend/src/components/ClientAllocations/ClientAllocations.js +++ b/frontend/src/components/ClientAllocations/ClientAllocations.js @@ -1,23 +1,23 @@ -import React, { PureComponent, PropTypes } from 'react' +import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' +import { WATCH_ALLOCS, UNWATCH_ALLOCS } from '../../sagas/event' import AllocationList from '../AllocationList/AllocationList' -class ClientAllocations extends PureComponent { +class ClientAllocations extends Component { + + componentWillMount () { + this.props.dispatch({ type: WATCH_ALLOCS}) + } + + componentWillUnmount () { + this.props.dispatch({ type: UNWATCH_ALLOCS }) + } render () { const nodeId = this.props.params.nodeId const allocs = this.props.allocations.filter(allocation => allocation.NodeID === nodeId) - return ( -
    - -
    - ) + return } } @@ -34,7 +34,8 @@ ClientAllocations.defaultProps = { ClientAllocations.propTypes = { allocations: PropTypes.array.isRequired, params: PropTypes.object.isRequired, - location: PropTypes.object.isRequired + location: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired, } export default connect(mapStateToProps)(ClientAllocations) diff --git a/frontend/src/components/ClientEvaluations/ClientEvaluations.js b/frontend/src/components/ClientEvaluations/ClientEvaluations.js index 2c931dd9..2328645b 100644 --- a/frontend/src/components/ClientEvaluations/ClientEvaluations.js +++ b/frontend/src/components/ClientEvaluations/ClientEvaluations.js @@ -1,18 +1,23 @@ -import React, { PureComponent, PropTypes } from 'react' +import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' +import { WATCH_EVALS, UNWATCH_EVALS } from '../../sagas/event' import EvaluationList from '../EvaluationList/EvaluationList' -class ClientEvaluations extends PureComponent { +class ClientEvaluations extends Component { + + componentWillMount () { + this.props.dispatch({ type: WATCH_EVALS}) + } + + componentWillUnmount () { + this.props.dispatch({ type: UNWATCH_EVALS }) + } render () { const nodeId = this.props.params.nodeId const evals = this.props.evaluations.filter(evaluation => evaluation.NodeID === nodeId) - return ( -
    - -
    - ) + return } } @@ -27,7 +32,8 @@ ClientEvaluations.defaultProps = { ClientEvaluations.propTypes = { evaluations: PropTypes.array.isRequired, - params: PropTypes.object.isRequired + params: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired, } export default connect(mapStateToProps)(ClientEvaluations) diff --git a/frontend/src/components/ClientInfo/ClientInfo.js b/frontend/src/components/ClientInfo/ClientInfo.js index e3501e3d..7e15fa54 100644 --- a/frontend/src/components/ClientInfo/ClientInfo.js +++ b/frontend/src/components/ClientInfo/ClientInfo.js @@ -1,6 +1,8 @@ import React, { PropTypes } from 'react' import { connect } from 'react-redux' import MetaPayload from '../MetaPayload/MetaPayload' +import { Grid, Row, Col } from 'react-flexbox-grid' +import { Card, CardTitle, CardText } from 'material-ui/Card' const nodeProps = [ 'ID', @@ -25,47 +27,87 @@ const withPrefix = function withPrefix (obj, prefix) { } const ClientInfo = ({ node }) => -
    -
    -
    - Client Properties -
    - { nodeProps.map(nodeProp => -
    -
    { nodeProp }
    -
    { node[nodeProp] }
    -
    - )} -
    -
    -
    - Meta Properties - -
    -
    -
    -
    - CPU Attributes - -
    -
    - Driver Attributes - -
    -
    - Kernel Attributes - -
    -
    - Unique Attributes - -
    -
    - Nomad Attributes - -
    -
    -
    + + + + + + +
    + { nodeProps.map(nodeProp => +
    +
    { nodeProp }
    +
    { node[nodeProp] }
    +
    + )} +
    +
    +
    + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    function mapStateToProps ({ node }) { return { node } diff --git a/frontend/src/components/ClientRaw/ClientRaw.js b/frontend/src/components/ClientRaw/ClientRaw.js index de639dc9..049cab9f 100644 --- a/frontend/src/components/ClientRaw/ClientRaw.js +++ b/frontend/src/components/ClientRaw/ClientRaw.js @@ -1,14 +1,15 @@ import React, { PropTypes } from 'react' import { connect } from 'react-redux' - +import { Card, CardTitle, CardText } from 'material-ui/Card' import RawJson from '../RawJson/RawJson' const ClientRaw = ({ node }) => -
    -
    + + + -
    -
    + + function mapStateToProps ({ node }) { return { node } diff --git a/frontend/src/components/ClientTopbar/ClientTopbar.js b/frontend/src/components/ClientTopbar/ClientTopbar.js new file mode 100644 index 00000000..36aea93c --- /dev/null +++ b/frontend/src/components/ClientTopbar/ClientTopbar.js @@ -0,0 +1,85 @@ +import FontIcon from 'material-ui/FontIcon' +import React, { PureComponent, PropTypes } from 'react' +import { BottomNavigation, BottomNavigationItem } from 'material-ui/BottomNavigation' +import { withRouter } from 'react-router' + +const infoIcon = info_outline +const allocationIcon = apps +const evaluationIcon = share +const rawIcon = code + +class _ClientTopbar extends PureComponent { + + handleActive (tab) { + let path = location.pathname.split('/') + path.pop() + path = path.join('/') + this.props.router.push(path + '/' + tab) + } + + getActiveTab () { + const location = this.props.location + const end = location.pathname.split('/').pop() + + if (end.startsWith('info')) { + return 0 + } + + if (end.startsWith('allocations')) { + return 1 + } + + if (end.startsWith('evaluations')) { + return 2 + } + + if (end.startsWith('raw')) { + return 3 + } + + return 0 + } + + getStyle () { + return { + borderBottom: '1px solid #e0e0e0', + marginBottom: 10 + } + } + + render () { + return ( + + this.handleActive('info') } + /> + this.handleActive('allocations') } + /> + this.handleActive('evaluations') } + /> + this.handleActive('raw') } + /> + + ) + } +} + +_ClientTopbar.propTypes = { + router: PropTypes.object.isRequired, + location: PropTypes.object.isRequired +} + +const ClientTopbar = withRouter(_ClientTopbar) + +export default ClientTopbar diff --git a/frontend/src/components/EvaluationInfo/EvaluationInfo.js b/frontend/src/components/EvaluationInfo/EvaluationInfo.js index 4edc0b82..75fc2d8a 100644 --- a/frontend/src/components/EvaluationInfo/EvaluationInfo.js +++ b/frontend/src/components/EvaluationInfo/EvaluationInfo.js @@ -1,5 +1,7 @@ import React, { PropTypes } from 'react' import { connect } from 'react-redux' +import { Grid, Row, Col } from 'react-flexbox-grid' +import { Card, CardTitle, CardText } from 'material-ui/Card' const evaluationProps = [ 'ID', @@ -11,21 +13,26 @@ const evaluationProps = [ ] const EvaluationInfo = ({ evaluation }) => -
    -
    -
    - Evaluation Properties -
    - { evaluationProps.map(evalProp => -
    -
    { evalProp }
    -
    { evaluation[evalProp] }
    -
    - )} -
    -
    -
    -
    + + + + + + +
    + { evaluationProps.map(evalProp => +
    +
    { evalProp }
    +
    { evaluation[evalProp] }
    +
    + )} +
    +
    +
    + +
    +
    + function mapStateToProps ({ evaluation }) { return { evaluation } diff --git a/frontend/src/components/EvaluationList/EvaluationList.js b/frontend/src/components/EvaluationList/EvaluationList.js index aeaadd40..18f1a8c7 100644 --- a/frontend/src/components/EvaluationList/EvaluationList.js +++ b/frontend/src/components/EvaluationList/EvaluationList.js @@ -1,49 +1,49 @@ import React, { PropTypes } from 'react' +import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from '../Table' +import { Card, CardText } from 'material-ui/Card' import EvaluationLink from '../EvaluationLink/EvaluationLink' import JobLink from '../JobLink/JobLink' -const EvaluationList = ({ evaluations, containerClassName }) => -
    -
    - - - - - - - - - - - - - - +const EvaluationList = ({ evaluations }) => + + +
    IDJobTypePriorityStatusStatus DescriptionParentTriggered by
    + + + ID + Job + Type + Priority + Status + Status Description + Parent + Triggered by + + + { evaluations.map(evaluation => - - - - - - - - - - + + + + { evaluation.Type } + { evaluation.Priority } + { evaluation.Status } + { evaluation.StatusDescription } + + { evaluation.TriggeredBy } + )} - -
    { evaluation.Type }{ evaluation.Priority }{ evaluation.Status }{ evaluation.StatusDescription }{ evaluation.TriggeredBy }
    -
    -
    + + + + EvaluationList.defaultProps = { - evaluations: [], - containerClassName: '' + evaluations: [] } EvaluationList.propTypes = { - evaluations: PropTypes.array.isRequired, - containerClassName: PropTypes.string.isRequired + evaluations: PropTypes.array.isRequired } export default EvaluationList diff --git a/frontend/src/components/EvaluationRaw/EvaluationRaw.js b/frontend/src/components/EvaluationRaw/EvaluationRaw.js index df8995a0..f7e4f023 100644 --- a/frontend/src/components/EvaluationRaw/EvaluationRaw.js +++ b/frontend/src/components/EvaluationRaw/EvaluationRaw.js @@ -1,12 +1,15 @@ import React, { PropTypes } from 'react' import { connect } from 'react-redux' - +import { Card, CardTitle, CardText } from 'material-ui/Card' import RawJson from '../RawJson/RawJson' const EvaluationRaw = ({ evaluation }) => -
    - -
    + + + + + + function mapStateToProps ({ evaluation }) { return { evaluation } diff --git a/frontend/src/components/EvaluationTopbar/EvaluationTopbar.js b/frontend/src/components/EvaluationTopbar/EvaluationTopbar.js new file mode 100644 index 00000000..56386266 --- /dev/null +++ b/frontend/src/components/EvaluationTopbar/EvaluationTopbar.js @@ -0,0 +1,75 @@ +import FontIcon from 'material-ui/FontIcon' +import React, { PureComponent, PropTypes } from 'react' +import { BottomNavigation, BottomNavigationItem } from 'material-ui/BottomNavigation' +import { withRouter } from 'react-router' + +const infoIcon = info_outline +const allocationIcon = apps +const rawIcon = code + +class _EvaluationTopbar extends PureComponent { + + handleActive (tab) { + let path = location.pathname.split('/') + path.pop() + path = path.join('/') + this.props.router.push(path + '/' + tab) + } + + getActiveTab () { + const location = this.props.location + const end = location.pathname.split('/').pop() + + if (end.startsWith('info')) { + return 0 + } + + if (end.startsWith('allocations')) { + return 1 + } + + if (end.startsWith('raw')) { + return 2 + } + + return 0 + } + + getStyle () { + return { + borderBottom: '1px solid #e0e0e0', + marginBottom: 10 + } + } + + render () { + return ( + + this.handleActive('info') } + /> + this.handleActive('allocations') } + /> + this.handleActive('raw') } + /> + + ) + } +} + +_EvaluationTopbar.propTypes = { + router: PropTypes.object.isRequired, + location: PropTypes.object.isRequired +} + +const ViewEvaluationTopbar = withRouter(_EvaluationTopbar) + +export default ViewEvaluationTopbar diff --git a/frontend/src/components/JobAllocations/JobAllocations.js b/frontend/src/components/JobAllocations/JobAllocations.js index dbab2522..f8e07e30 100644 --- a/frontend/src/components/JobAllocations/JobAllocations.js +++ b/frontend/src/components/JobAllocations/JobAllocations.js @@ -1,8 +1,19 @@ -import React, { PureComponent, PropTypes } from 'react' +import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' import AllocationList from '../AllocationList/AllocationList' +import { WATCH_ALLOCS, UNWATCH_ALLOCS, WATCH_NODES, UNWATCH_NODES } from '../../sagas/event' -class JobAllocations extends PureComponent { +class JobAllocations extends Component { + + componentWillMount () { + this.props.dispatch({ type: WATCH_ALLOCS }) + this.props.dispatch({ type: WATCH_NODES }) + } + + componentWillUnmount () { + this.props.dispatch({ type: UNWATCH_ALLOCS }) + this.props.dispatch({ type: UNWATCH_NODES }) + } render () { const allocs = this.props.allocations.filter(allocation => allocation.JobID === this.props.params.jobId) @@ -33,7 +44,8 @@ JobAllocations.propTypes = { allocations: PropTypes.array.isRequired, params: PropTypes.object.isRequired, nodes: PropTypes.array.isRequired, - location: PropTypes.object.isRequired + location: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired, } export default connect(mapStateToProps)(JobAllocations) diff --git a/frontend/src/components/JobEvaluations/JobEvaluations.js b/frontend/src/components/JobEvaluations/JobEvaluations.js index 46d7ef7b..580fd646 100644 --- a/frontend/src/components/JobEvaluations/JobEvaluations.js +++ b/frontend/src/components/JobEvaluations/JobEvaluations.js @@ -1,8 +1,17 @@ -import React, { PureComponent, PropTypes } from 'react' +import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' import EvaluationList from '../EvaluationList/EvaluationList' +import { WATCH_EVALS, UNWATCH_EVALS } from '../../sagas/event' -class JobEvaluations extends PureComponent { +class JobEvaluations extends Component { + + componentWillMount () { + this.props.dispatch({ type: WATCH_EVALS }) + } + + componentWillUnmount () { + this.props.dispatch({ type: UNWATCH_EVALS }) + } render () { const jobId = this.props.params.jobId @@ -27,7 +36,8 @@ JobEvaluations.defaultProps = { JobEvaluations.propTypes = { evaluations: PropTypes.array.isRequired, - params: PropTypes.object.isRequired + params: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired, } export default connect(mapStateToProps)(JobEvaluations) diff --git a/frontend/src/components/JobRaw/JobRaw.js b/frontend/src/components/JobRaw/JobRaw.js index ea0a4547..13969967 100644 --- a/frontend/src/components/JobRaw/JobRaw.js +++ b/frontend/src/components/JobRaw/JobRaw.js @@ -1,12 +1,15 @@ import React, { PropTypes } from 'react' import { connect } from 'react-redux' - +import { Card, CardTitle, CardText } from 'material-ui/Card' import RawJson from '../RawJson/RawJson' const JobRaw = ({ job }) => -
    - -
    + + + + + + function mapStateToProps ({ job }) { return { job } diff --git a/frontend/src/components/JobTaskGroups/JobTaskGroups.js b/frontend/src/components/JobTaskGroups/JobTaskGroups.js index 92e29791..9781ed39 100644 --- a/frontend/src/components/JobTaskGroups/JobTaskGroups.js +++ b/frontend/src/components/JobTaskGroups/JobTaskGroups.js @@ -1,5 +1,8 @@ import React, { PropTypes } from 'react' import { connect } from 'react-redux' +import { Grid, Row, Col } from 'react-flexbox-grid' +import { Card, CardTitle, CardText } from 'material-ui/Card' +import { TableRow, TableRowColumn } from '../Table' import JobLink from '../JobLink/JobLink' import TableHelper from '../TableHelper/TableHelper' import RawJson from '../RawJson/RawJson' @@ -18,14 +21,14 @@ const JobTaskGroups = ({ job, location }) => { job.TaskGroups.forEach((taskGroup) => { taskGroups.push( - - - { taskGroup.Name } - { taskGroup.Count } - - { taskGroup.RestartPolicy.Mode } - - ) + + + { taskGroup.Name } + { taskGroup.Count } + + { taskGroup.RestartPolicy.Mode } + + ) }) let taskGroupId = location.query.taskGroupId @@ -34,31 +37,35 @@ const JobTaskGroups = ({ job, location }) => { if (!taskGroupId && job.TaskGroups.length === 1) { taskGroupId = job.TaskGroups[0].ID } + return ( -
    -
    -
    - Task Groups - { (taskGroups.length > 0) ? - - : null - } -
    -
    - Task Group: { taskGroupId } - { job.TaskGroups - .filter(taskGroup => taskGroup.ID === taskGroupId) - .map(taskGroup => ) - .pop() - } -
    -
    -
    - ) + + + + + + + { (taskGroups.length > 0) + ? + : null + } + + + + + + + + { job.TaskGroups + .filter(taskGroup => taskGroup.ID === taskGroupId) + .map(taskGroup => ) + .pop() + } + + + + + ) } function mapStateToProps ({ job }) { diff --git a/frontend/src/components/ViewJobTopbar/ViewJobTopbar.js b/frontend/src/components/JobTopbar/JobTopbar.js similarity index 92% rename from frontend/src/components/ViewJobTopbar/ViewJobTopbar.js rename to frontend/src/components/JobTopbar/JobTopbar.js index b6b953bb..eccb3484 100644 --- a/frontend/src/components/ViewJobTopbar/ViewJobTopbar.js +++ b/frontend/src/components/JobTopbar/JobTopbar.js @@ -7,9 +7,9 @@ const infoIcon = info_outline const allocationIcon = apps const evaluationIcon = share const taskGroupIcon = layers -const rawIcon = highlight +const rawIcon = code -class _ViewJobTopbar extends PureComponent { +class _JobTopbar extends PureComponent { handleActive (tab) { let path = location.pathname.split('/') @@ -85,11 +85,11 @@ class _ViewJobTopbar extends PureComponent { } } -_ViewJobTopbar.propTypes = { +_JobTopbar.propTypes = { router: PropTypes.object.isRequired, location: PropTypes.object.isRequired } -const ViewJobTopbar = withRouter(_ViewJobTopbar) +const ViewJobTopbar = withRouter(_JobTopbar) export default ViewJobTopbar diff --git a/frontend/src/components/ViewServerTopbar/ViewServerTopbar.js b/frontend/src/components/ServerTopbar/ServerTopbar.js similarity index 95% rename from frontend/src/components/ViewServerTopbar/ViewServerTopbar.js rename to frontend/src/components/ServerTopbar/ServerTopbar.js index bdb2c3dc..c56764bd 100644 --- a/frontend/src/components/ViewServerTopbar/ViewServerTopbar.js +++ b/frontend/src/components/ServerTopbar/ServerTopbar.js @@ -4,7 +4,7 @@ import { BottomNavigation, BottomNavigationItem } from 'material-ui/BottomNaviga import { withRouter } from 'react-router' const infoIcon = info_outline -const rawIcon = highlight +const rawIcon = code class _ViewServerTopbar extends PureComponent { diff --git a/frontend/src/components/Tabs/Tabs.js b/frontend/src/components/Tabs/Tabs.js deleted file mode 100644 index 5b9659c1..00000000 --- a/frontend/src/components/Tabs/Tabs.js +++ /dev/null @@ -1,31 +0,0 @@ -import React, { PropTypes } from 'react' -import { Link } from 'react-router' - -const Tabs = ({ children, tabs, tabSlug, basePath }) => -
    -
      - {tabs.map(tab => -
    • - - { tab.name } - -
    • ) - } -
    -
    - {children} -
    -
    - -Tabs.propTypes = { - tabs: PropTypes.array.isRequired, - tabSlug: PropTypes.string.isRequired, - basePath: PropTypes.string.isRequired, - children: PropTypes.object.isRequired -} - -export default Tabs diff --git a/frontend/src/components/app.js b/frontend/src/components/app.js index cca923c4..b1f39d9c 100644 --- a/frontend/src/components/app.js +++ b/frontend/src/components/app.js @@ -3,7 +3,7 @@ import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider' import injectTapEventPlugin from 'react-tap-event-plugin' import { green800, green900 } from 'material-ui/styles/colors' import getMuiTheme from 'material-ui/styles/getMuiTheme' -import Topbar from './Topbar/Topbar' +import AppTopbar from './AppTopbar/AppTopbar' const muiTheme = getMuiTheme({ palette: { @@ -28,7 +28,7 @@ class App extends PureComponent { return (
    - + { this.props.children }
    diff --git a/frontend/src/containers/allocation.js b/frontend/src/containers/allocation.js index 927b86e5..3600fc55 100644 --- a/frontend/src/containers/allocation.js +++ b/frontend/src/containers/allocation.js @@ -1,6 +1,6 @@ import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' -import ViewAllocationTopbar from '../components/ViewAllocationTopbar/ViewAllocationTopbar' +import AllocationTopbar from '../components/AllocationTopbar/AllocationTopbar' import { WATCH_ALLOC, UNWATCH_ALLOC } from '../sagas/event' class Allocation extends Component { @@ -26,7 +26,7 @@ class Allocation extends Component { return (
    - +

    Allocation: { this.props.allocation.Name }

    diff --git a/frontend/src/containers/client.js b/frontend/src/containers/client.js index 1ba3e601..67078fe6 100644 --- a/frontend/src/containers/client.js +++ b/frontend/src/containers/client.js @@ -1,69 +1,33 @@ import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' -import Tabs from '../components/Tabs/Tabs' +import ClientTopbar from '../components/ClientTopbar/ClientTopbar' import { WATCH_NODE, UNWATCH_NODE } from '../sagas/event' class Client extends Component { - constructor (props) { - super(props) - - this.state = { - tabs: [ - { - name: 'Info', - path: 'info' - }, - { - name: 'Allocations', - path: 'allocations' - }, - { - name: 'Evaluations', - path: 'evaluations' - }, - { - name: 'Raw', - path: 'raw' - } - ] - } - } - componentWillMount () { - this.props.dispatch({ - type: WATCH_NODE, - payload: this.props.params.nodeId - }) + this.props.dispatch({ type: WATCH_NODE, payload: this.props.params.nodeId }) } componentWillUnmount () { - this.props.dispatch({ - type: UNWATCH_NODE, - payload: this.props.params.nodeId - }) + this.props.dispatch({ type: UNWATCH_NODE, payload: this.props.params.nodeId }) } render () { - if (this.props.node == null) return (null) - - const path = this.props.location.pathname - const tabSlug = path.split('/').pop() - const basePath = path.substring(0, path.lastIndexOf('/')) + if (this.props.node == null) { + return null + } return ( -
    -
    -
    -
    -

    Client: { this.props.node.Name }

    -
    -
    - - { this.props.children } - -
    -
    +
    + + +
    +

    Client: { this.props.node.Name }

    + +
    + + { this.props.children }
    ) diff --git a/frontend/src/containers/clients.js b/frontend/src/containers/clients.js index f6b2ca90..89017104 100644 --- a/frontend/src/containers/clients.js +++ b/frontend/src/containers/clients.js @@ -1,5 +1,7 @@ import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' +import { Card, CardText } from 'material-ui/Card' +import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from '../components/Table' import { WATCH_NODES, UNWATCH_NODES } from '../sagas/event' import ClientLink from '../components/ClientLink/ClientLink' import FormatBoolean from '../components/FormatBoolean/FormatBoolean' @@ -17,40 +19,39 @@ class Clients extends Component { render() { return ( -
    -
    -
    -
    -

    Clients

    -
    -
    - - - - - - - - - - - - - { this.props.nodes.map(node => - - - - - - - - - )} - -
    IDNameStatusDrainDatacenterClass
    { node.Name }{ node.Datacenter }{ node.NodeClass ? node.NodeClass : ''}
    -
    -
    -
    +
    + + + + + + ID + Name + Status + Drain + Datacenter + Class + + + + { this.props.nodes.map((node) => { + return ( + + + { node.Name } + + + { node.Datacenter } + { node.NodeClass ? node.NodeClass : ''} + + + ) + }) + } + +
    +
    +
    ) } diff --git a/frontend/src/containers/evaluation.js b/frontend/src/containers/evaluation.js index 295c91b1..55cfd7eb 100644 --- a/frontend/src/containers/evaluation.js +++ b/frontend/src/containers/evaluation.js @@ -1,65 +1,35 @@ import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' -import Tabs from '../components/Tabs/Tabs' -import { WATCH_EVAL, UNWATCH_EVAL } from '../sagas/event' +import EvaluationTopbar from '../components/EvaluationTopbar/EvaluationTopbar' +import { WATCH_EVAL, UNWATCH_EVAL, WATCH_ALLOCS, UNWATCH_ALLOCS } from '../sagas/event' class Evaluation extends Component { - constructor (props) { - super(props) - - this.state = { - tabs: [ - { - name: 'Info', - path: 'info' - }, - { - name: 'Allocations', - path: 'allocations' - }, - { - name: 'Raw', - path: 'raw' - } - ] - } - } - componentWillMount () { - this.props.dispatch({ - type: WATCH_EVAL, - payload: this.props.params.evalId - }) + this.props.dispatch({ type: WATCH_EVAL, payload: this.props.params.evalId }) + this.props.dispatch({ type: WATCH_ALLOCS }) } componentWillUnmount () { - this.props.dispatch({ - type: UNWATCH_EVAL, - payload: this.props.params.evalId - }) + this.props.dispatch({ type: UNWATCH_EVAL, payload: this.props.params.evalId }) + this.props.dispatch({ type: UNWATCH_ALLOCS }) } render () { - if (this.props.evaluation == null) return (null) - - const path = this.props.location.pathname - const tabSlug = path.split('/').pop() - const basePath = path.substring(0, path.lastIndexOf('/')) + if (this.props.evaluation == null) { + return (null) + } return ( -
    -
    -
    -
    -

    Evaluation: { this.props.evaluation.ID }

    -
    -
    - - { this.props.children } - -
    -
    +
    + + +
    +

    Evaluation: { this.props.evaluation.ID }

    + +
    + + { this.props.children }
    ) @@ -74,7 +44,6 @@ Evaluation.propTypes = { dispatch: PropTypes.func.isRequired, params: PropTypes.object.isRequired, evaluation: PropTypes.object.isRequired, - location: PropTypes.object.isRequired, children: PropTypes.object.isRequired } diff --git a/frontend/src/containers/evaluations.js b/frontend/src/containers/evaluations.js index 94548eb1..c783d5fd 100644 --- a/frontend/src/containers/evaluations.js +++ b/frontend/src/containers/evaluations.js @@ -14,18 +14,7 @@ class Evaluations extends Component { } render() { - return ( -
    -
    -
    -
    -

    Evaluations

    -
    - -
    -
    -
    - ) + return } } diff --git a/frontend/src/containers/job.js b/frontend/src/containers/job.js index 38ec1483..1f7ed416 100644 --- a/frontend/src/containers/job.js +++ b/frontend/src/containers/job.js @@ -1,6 +1,6 @@ import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' -import ViewJobTopbar from '../components/ViewJobTopbar/ViewJobTopbar' +import JobTopbar from '../components/JobTopbar/JobTopbar' import { WATCH_JOB, UNWATCH_JOB } from '../sagas/event' class Job extends Component { @@ -20,7 +20,7 @@ class Job extends Component { return (
    - +

    Job: { this.props.job.Name }

    diff --git a/frontend/src/containers/jobs.js b/frontend/src/containers/jobs.js index cc36d258..bcdd7cee 100644 --- a/frontend/src/containers/jobs.js +++ b/frontend/src/containers/jobs.js @@ -114,7 +114,7 @@ class Jobs extends Component { return (
    - +   diff --git a/frontend/src/containers/server.js b/frontend/src/containers/server.js index 3f172a04..00fdc654 100644 --- a/frontend/src/containers/server.js +++ b/frontend/src/containers/server.js @@ -1,6 +1,6 @@ import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' -import ViewServerTopbar from '../components/ViewServerTopbar/ViewServerTopbar' +import ServerTopbar from '../components/ServerTopbar/ServerTopbar' import { WATCH_MEMBER, UNWATCH_MEMBER } from '../sagas/event' class Server extends Component { @@ -20,7 +20,7 @@ class Server extends Component { return (
    - +

    Server: { this.props.member.Name }

    diff --git a/frontend/src/containers/servers.js b/frontend/src/containers/servers.js index 665ab95c..cb4fcb7b 100644 --- a/frontend/src/containers/servers.js +++ b/frontend/src/containers/servers.js @@ -1,6 +1,6 @@ import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' -import { Card, CardHeader, CardText } from 'material-ui/Card' +import { Card, CardText } from 'material-ui/Card' import { WATCH_MEMBERS, UNWATCH_MEMBERS } from '../sagas/event' import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from '../components/Table' import ServerLink from '../components/ServerLink/ServerLink' @@ -20,7 +20,6 @@ class Servers extends Component { return (
    - From aac69200c23f9e328ff66e541b3647efe0a7dfc2 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Thu, 8 Dec 2016 21:04:00 +0100 Subject: [PATCH 33/45] style cluster status page --- frontend/package.json | 2 + .../components/ClusterEvents/ClusterEvents.js | 75 ++++++++ .../ClusterStatistics/ClusterStatistics.js} | 16 +- .../src/components/Progressbar/Progressbar.js | 173 ++++++++++++------ frontend/src/containers/cluster.js | 60 ++++-- frontend/src/containers/events.js | 77 -------- frontend/yarn.lock | 100 +++++++++- 7 files changed, 336 insertions(+), 167 deletions(-) create mode 100644 frontend/src/components/ClusterEvents/ClusterEvents.js rename frontend/src/{containers/statistics.js => components/ClusterStatistics/ClusterStatistics.js} (69%) delete mode 100644 frontend/src/containers/events.js diff --git a/frontend/package.json b/frontend/package.json index 3dbc5c8c..ee4353a4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -39,6 +39,7 @@ "node-uuid": "^1.4.7", "react": "^15.4.1", "react-addons-perf": "^15.4.1", + "react-addons-transition-group": "^15.4.1", "react-bootstrap": "^0.30.7", "react-dom": "^15.4.1", "react-flexbox-grid": "^0.10.2", @@ -46,6 +47,7 @@ "react-router": "^3.0.0", "react-tap-event-plugin": "^2.0.1", "react-tooltip": "^3.1.8", + "recharts": "^0.19.0", "recompose": "^0.20.2", "redux": "^3.6.0", "redux-saga": "^0.13.0", diff --git a/frontend/src/components/ClusterEvents/ClusterEvents.js b/frontend/src/components/ClusterEvents/ClusterEvents.js new file mode 100644 index 00000000..4339a42c --- /dev/null +++ b/frontend/src/components/ClusterEvents/ClusterEvents.js @@ -0,0 +1,75 @@ +import React, { Component, PropTypes } from 'react' +import { connect } from 'react-redux' +import AllocationLink from '../AllocationLink/AllocationLink' +import FormatTime from '../FormatTime/FormatTime' +import TableHelper from '../TableHelper/TableHelper' +import { TableRow, TableRowColumn } from '../Table' +import { Card, CardTitle, CardText } from 'material-ui/Card' +import { WATCH_ALLOCS, UNWATCH_ALLOCS } from '../../sagas/event' + +class ClusterEvents extends Component { + + componentWillMount () { + this.props.dispatch({ type: WATCH_ALLOCS }) + } + + componentWillUnmount () { + this.props.dispatch({ type: UNWATCH_ALLOCS }) + } + + render () { + const taskEvents = [] + this.props.allocations.forEach((allocation) => { + if (allocation.TaskStates != null) { + Object.keys(allocation.TaskStates).forEach((task) => { + allocation.TaskStates[task].Events.reverse().forEach((event) => { + if (taskEvents.length === 10) return + const eventID = `${task}.${event.Time}` + taskEvents.push( + + + + { allocation.JobID }.{ task } + + + { event.Type } + { event.KillError || + event.DriverError || + event.DownloadError || + event.RestartReason || + event.Message || + '' + } + + + + ) + }) + }) + } + }) + + return ( + + Task events + + + + + ) + } +} + +function mapStateToProps ({ allocations }) { + return { allocations } +} + +ClusterEvents.propTypes = { + allocations: PropTypes.array.isRequired, + dispatch: PropTypes.func.isRequired, +} + +export default connect(mapStateToProps)(ClusterEvents) diff --git a/frontend/src/containers/statistics.js b/frontend/src/components/ClusterStatistics/ClusterStatistics.js similarity index 69% rename from frontend/src/containers/statistics.js rename to frontend/src/components/ClusterStatistics/ClusterStatistics.js index e2ca8449..b012d3f2 100644 --- a/frontend/src/containers/statistics.js +++ b/frontend/src/components/ClusterStatistics/ClusterStatistics.js @@ -1,8 +1,8 @@ import React, { PropTypes } from 'react' import { connect } from 'react-redux' -import Progressbar from '../components/Progressbar/Progressbar' +import Progressbar from '../Progressbar/Progressbar' -const Statistics = ({ jobs }) => { +const ClusterStatistics = ({ jobs }) => { const clientStatus = { Running: 0, Starting: 0 @@ -33,21 +33,15 @@ const Statistics = ({ jobs }) => { delete clientStatus.Complete - return ( -
    -
    - -
    -
    - ) + return } function mapStateToProps ({ jobs }) { return { jobs } } -Statistics.propTypes = { +ClusterStatistics.propTypes = { jobs: PropTypes.array.isRequired } -export default connect(mapStateToProps)(Statistics) +export default connect(mapStateToProps)(ClusterStatistics) diff --git a/frontend/src/components/Progressbar/Progressbar.js b/frontend/src/components/Progressbar/Progressbar.js index a34e5a78..33daa804 100644 --- a/frontend/src/components/Progressbar/Progressbar.js +++ b/frontend/src/components/Progressbar/Progressbar.js @@ -1,37 +1,91 @@ import React, { Component, PropTypes } from 'react' -import { ProgressBar } from 'react-bootstrap' +import { ResponsiveContainer, PieChart, Pie, Cell, Sector } from 'recharts'; +import { green500, red500, blue500, yellow500 } from 'material-ui/styles/colors' +import { Card, CardTitle, CardText } from 'material-ui/Card' + +// +// borrowed from http://recharts.org/examples#CustomActiveShapePieChart +// class Progressbar extends Component { + constructor(props) { + super(props); + this.state = { activeIndex: 0, showLabel: true } + } + + onPieEnter(data, index) { + this.setState({ activeIndex: index, showLabel: false }); + } + + onPieLeave(data, index) { + this.setState({ showLabel: true }) + } + + renderActiveShape(props) { + const { cx, cy, innerRadius, outerRadius, startAngle, endAngle, fill, payload, percent } = props; + const p = (percent * 100).toFixed(0) + + const textY = cy - 25 + + return ( + + + { payload.name } + { payload.value } + { p }% + + + + + ) + } + colorIndex (index) { return { - // client status - ready: 'success', - initializing: 'warning', - down: 'danger', - - // server status - alive: 'success', - leaving: 'warning', - left: 'danger', - shutdown: 'danger', - - // job status - running: 'success', - pending: 'warning', - dead: 'info', - - // job type - service: 'success', - batch: 'info', - system: 'primary', - - // task states - // running: 'success', - starting: 'warning', - queued: 'info', - failed: 'danger', - lost: 'danger' + // client status + ready: green500, + initializing: red500, + down: blue500, + + // server status + alive: green500, + leaving: red500, + left: blue500, + shutdown: yellow500, + + // job status + running: green500, + pending: red500, + dead: blue500, + + // job type + service: green500, + batch: red500, + system: blue500, + + // task states + // running: 'success', + starting: green500, + queued: red500, + failed: blue500, + lost: yellow500 }[index] } @@ -40,39 +94,40 @@ class Progressbar extends Component { const normalizedValues = {} keys.forEach(key => (normalizedValues[key.toLowerCase()] = this.props.data[key])) const normalizedKeys = keys.map(string => string.toLowerCase()) - const sum = normalizedKeys.reduce((previous, currentValue) => { - return previous + normalizedValues[currentValue] - }, 0) + + let data = normalizedKeys.map((index) => { + return { + name: index, + value: normalizedValues[index] + } + }) return ( -
    -
    -
    { this.props.title }
    - - - {normalizedKeys.map((index) => { - return ( - - ) - })} - - - {normalizedKeys.map((index) => { - return ( - - - { index } ({ normalizedValues[index] }) - - ) - })} -
    -
    + + + + + { this.onPieEnter(data, index) } } + onMouseLeave={ (data, index) => { this.onPieLeave(data, index) } } + > + + { + data.map((entry) => ) + } + + + + + ) } } diff --git a/frontend/src/containers/cluster.js b/frontend/src/containers/cluster.js index 84c20639..cc9cf5d5 100644 --- a/frontend/src/containers/cluster.js +++ b/frontend/src/containers/cluster.js @@ -1,11 +1,30 @@ import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' import Progressbar from '../components/Progressbar/Progressbar' -import Events from './events' -import Statistics from './statistics' +import ClusterEvents from '../components/ClusterEvents/ClusterEvents' +import ClusterStatistics from '../components/ClusterStatistics/ClusterStatistics' +import { Card, CardText } from 'material-ui/Card' +import { Grid, Row, Col } from 'react-flexbox-grid' +import { + WATCH_JOBS, UNWATCH_JOBS, + WATCH_NODES, UNWATCH_NODES, + WATCH_MEMBERS, UNWATCH_MEMBERS +} from '../sagas/event' class Cluster extends Component { + componentWillMount () { + this.props.dispatch({ type: WATCH_JOBS }) + this.props.dispatch({ type: WATCH_NODES }) + this.props.dispatch({ type: WATCH_MEMBERS }) + } + + componentWillUnmount () { + this.props.dispatch({ type: UNWATCH_JOBS }) + this.props.dispatch({ type: UNWATCH_NODES }) + this.props.dispatch({ type: UNWATCH_MEMBERS }) + } + getChartData () { const stats = { jobStatus: { @@ -51,24 +70,30 @@ class Cluster extends Component { const data = this.getChartData() return ( -
    -
    -
    + + +
    - -
    + +
    - -
    + +
    - -
    + +
    - - - - - + + + + + + + + + + + ) } } @@ -80,7 +105,8 @@ function mapStateToProps ({ jobs, nodes, members }) { Cluster.propTypes = { jobs: PropTypes.array.isRequired, nodes: PropTypes.array.isRequired, - members: PropTypes.array.isRequired + members: PropTypes.array.isRequired, + dispatch: PropTypes.func.isRequired, } export default connect(mapStateToProps)(Cluster) diff --git a/frontend/src/containers/events.js b/frontend/src/containers/events.js deleted file mode 100644 index eaccce8b..00000000 --- a/frontend/src/containers/events.js +++ /dev/null @@ -1,77 +0,0 @@ -import React, { Component, PropTypes } from 'react' -import { connect } from 'react-redux' -import AllocationLink from '../components/AllocationLink/AllocationLink' -import FormatTime from '../components/FormatTime/FormatTime' - -class Events extends Component { - - render () { - const taskEvents = [] - this.props.allocations.forEach((allocation) => { - if (allocation.TaskStates != null) { - Object.keys(allocation.TaskStates).forEach((task) => { - allocation.TaskStates[task].Events.reverse().forEach((event) => { - if (taskEvents.length === 10) return - const eventID = `${task}.${event.Time}` - taskEvents.push( - - - - - - - ) - }) - }) - } - }) - - return ( -
    -
    -
    -
    -

    Task Events

    -
    -
    -
    - - { allocation.JobID }.{ task } - - { event.Type }{ event.KillError || - event.DriverError || - event.DownloadError || - event.RestartReason || - event.Message || - '' - } -
    - - - - - - - - - - { taskEvents } - -
    TaskTypeMessageTime
    -
    -
    -
    -
    - ) - } -} - -function mapStateToProps ({ allocations }) { - return { allocations } -} - -Events.propTypes = { - allocations: PropTypes.array.isRequired -} - -export default connect(mapStateToProps)(Events) diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 7b43dd7c..a7281e8b 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1213,7 +1213,7 @@ core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" -core-js@^2.4.0: +core-js@^2.4.0, core-js@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" @@ -1357,6 +1357,60 @@ currently-unhandled@^0.4.1: dependencies: array-find-index "^1.0.1" +d3-array@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.0.2.tgz#174237bf356a852fadd6af87743d928631de7655" + +d3-collection@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.2.tgz#df5acb5400443e9eabe9c1379896c67e52426b39" + +d3-color@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.0.2.tgz#83cb4b3a9474e40795f009d97e97a15649830bbc" + +d3-format@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.0.2.tgz#138618320b4bbeb43b5c0ff30519079fbbd7375e" + +d3-interpolate@1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.1.2.tgz#b52e6927a04fe1fe2a4cffc139e5389ed3e5e790" + dependencies: + d3-color "1" + +d3-path@1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.3.tgz#60103d0dea9a6cd6ca58de86c6d56724002d3fde" + +d3-scale@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-1.0.4.tgz#50e28bf6a193b706745528515ed9b3d44205a033" + dependencies: + d3-array "1" + d3-collection "1" + d3-color "1" + d3-format "1" + d3-interpolate "1" + d3-time "1" + d3-time-format "2" + +d3-shape@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.0.4.tgz#145ee100ccbec42f8e3f1996cd05c786f79fe1c6" + dependencies: + d3-path "1" + +d3-time-format@2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.0.3.tgz#3241569b74ddc9c42e0689c0e8a903579fd6280a" + dependencies: + d3-time "1" + +d3-time@1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.0.4.tgz#2ceba09a76b7450c992a1ded4e10fc6195e69649" + d@^0.1.1, d@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" @@ -3293,6 +3347,10 @@ pbkdf2-compat@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/pbkdf2-compat/-/pbkdf2-compat-2.0.1.tgz#b6e0c8fa99494d94e0511575802a59a5c142f288" +performance-now@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" + pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -3685,6 +3743,12 @@ querystringify@0.0.x: version "0.0.4" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-0.0.4.tgz#0cf7f84f9463ff0ae51c4c4b142d95be37724d9c" +raf@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/raf/-/raf-3.3.0.tgz#93845eeffc773f8129039f677f80a36044eee2c3" + dependencies: + performance-now "~0.2.0" + randomatic@^1.1.3: version "1.1.6" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" @@ -3721,7 +3785,7 @@ react-addons-test-utils@^15.4.1: version "15.4.1" resolved "https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.4.1.tgz#1e4caab151bf27cce26df5f9cb714f4fd8359ae1" -react-addons-transition-group@^15.0.0: +"react-addons-transition-group@^0.14.0 || ^15.0.0", react-addons-transition-group@^15.0.0, react-addons-transition-group@^15.4.1: version "15.4.1" resolved "https://registry.yarnpkg.com/react-addons-transition-group/-/react-addons-transition-group-15.4.1.tgz#27d92717089c5e2db202e654a85b76a41b703acc" @@ -3793,6 +3857,10 @@ react-redux@^4.4.6: lodash "^4.2.0" loose-envify "^1.1.0" +react-resize-detector@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/react-resize-detector/-/react-resize-detector-0.3.3.tgz#ca07443072324843586666d9443a6356da7c0501" + react-router@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/react-router/-/react-router-3.0.0.tgz#3f313e4dbaf57048c48dd0a8c3cac24d93667dff" @@ -3803,6 +3871,14 @@ react-router@^3.0.0: loose-envify "^1.2.0" warning "^3.0.0" +react-smooth@^0.1.15: + version "0.1.17" + resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-0.1.17.tgz#0810990fdcbb5a5ceaf1fc4ebcb00f255f8e8935" + dependencies: + lodash "^4.16.4" + raf "^3.2.0" + react-addons-transition-group "^0.14.0 || ^15.0.0" + react-tap-event-plugin@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/react-tap-event-plugin/-/react-tap-event-plugin-2.0.1.tgz#316beb3bc6556e29ec869a7293e89c826a9074d2" @@ -3908,6 +3984,24 @@ readline2@^1.0.1: is-fullwidth-code-point "^1.0.0" mute-stream "0.0.5" +recharts-scale@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/recharts-scale/-/recharts-scale-0.2.1.tgz#378f543ed17c3245e4d9afb10aaf6298240d2fcb" + +recharts@^0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/recharts/-/recharts-0.19.0.tgz#228ac3558a60c48a14f54f087baafdb5d856398a" + dependencies: + classnames "^2.2.5" + core-js "^2.4.1" + d3-scale "^1.0.3" + d3-shape "^1.0.3" + lodash "^4.16.4" + react-resize-detector "^0.3.3" + react-smooth "^0.1.15" + recharts-scale "^0.2.1" + reduce-css-calc "^1.3.0" + rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" @@ -3930,7 +4024,7 @@ redent@^1.0.0: indent-string "^2.1.0" strip-indent "^1.0.1" -reduce-css-calc@^1.2.6: +reduce-css-calc@^1.2.6, reduce-css-calc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" dependencies: From c8825e9126be32754e6fd7372628e58f14df1d66 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Thu, 8 Dec 2016 21:08:44 +0100 Subject: [PATCH 34/45] fix title --- frontend/src/components/ClusterEvents/ClusterEvents.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/ClusterEvents/ClusterEvents.js b/frontend/src/components/ClusterEvents/ClusterEvents.js index 4339a42c..fdcc3bab 100644 --- a/frontend/src/components/ClusterEvents/ClusterEvents.js +++ b/frontend/src/components/ClusterEvents/ClusterEvents.js @@ -51,7 +51,7 @@ class ClusterEvents extends Component { return ( - Task events + Date: Thu, 8 Dec 2016 21:19:40 +0100 Subject: [PATCH 35/45] remove bootstrap (yay) --- frontend/package.json | 1 - .../AllocationFiles/AllocationFiles.js | 20 +++++++++++-------- .../components/ClusterEvents/ClusterEvents.js | 2 +- .../src/components/Progressbar/Progressbar.js | 2 +- frontend/src/containers/cluster.js | 1 - frontend/yarn.lock | 4 ---- 6 files changed, 14 insertions(+), 16 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index ee4353a4..073bee06 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -24,7 +24,6 @@ "dependencies": { "babel-polyfill": "^6.16.0", "babel-runtime": "^6.18.0", - "bootstrap": "^3.3.6", "chart.js": "^2.1.6", "classnames": "^2.2.5", "eslint-config-standard": "^6.2.1", diff --git a/frontend/src/components/AllocationFiles/AllocationFiles.js b/frontend/src/components/AllocationFiles/AllocationFiles.js index 3828f183..3aaa8c5a 100644 --- a/frontend/src/components/AllocationFiles/AllocationFiles.js +++ b/frontend/src/components/AllocationFiles/AllocationFiles.js @@ -2,7 +2,7 @@ import React, { Component, PropTypes } from 'react' import { Grid, Row, Col } from 'react-flexbox-grid' import ReactTooltip from 'react-tooltip' import { connect } from 'react-redux' -import { Button } from 'react-bootstrap' +import RaisedButton from 'material-ui/RaisedButton'; import Menu from 'material-ui/Menu' import MenuItem from 'material-ui/MenuItem' import FontIcon from 'material-ui/FontIcon' @@ -309,13 +309,17 @@ class AllocationFiles extends Component { const baseUrl = `${location.protocol}//${hostname}` const downloadPath = `download${this.props.file.File}` - const downloadBtn = this.props.file.File ? '' : - (
    - - - { oversizedWarning } - -
    ) + const downloadBtn = this.props.file.File.indexOf('<') >= 0 + ? '' + : ( +
    + + + { oversizedWarning } + + + ) const title = Current path: {this.props.location.query.path || '/'} const padding = { padding: 10 } diff --git a/frontend/src/components/ClusterEvents/ClusterEvents.js b/frontend/src/components/ClusterEvents/ClusterEvents.js index fdcc3bab..f95b3e56 100644 --- a/frontend/src/components/ClusterEvents/ClusterEvents.js +++ b/frontend/src/components/ClusterEvents/ClusterEvents.js @@ -51,7 +51,7 @@ class ClusterEvents extends Component { return ( - + Date: Fri, 9 Dec 2016 10:27:42 +0100 Subject: [PATCH 36/45] wrap all tables in a responsive table handler --- frontend/assets/nomad-ui.css | 10 ++++++++++ frontend/index.html.ejs | 3 ++- frontend/src/components/Table/Table.js | 8 ++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/frontend/assets/nomad-ui.css b/frontend/assets/nomad-ui.css index 8e3dae60..0dbf9f7f 100644 --- a/frontend/assets/nomad-ui.css +++ b/frontend/assets/nomad-ui.css @@ -67,3 +67,13 @@ code { th { text-align: left } + +.table-responsive { + border: 0; + width: 100%; + margin-bottom: 15px; + overflow-x: scroll; + overflow-y: hidden; + -ms-overflow-style: -ms-autohiding-scrollbar; + -webkit-overflow-scrolling: touch; +} diff --git a/frontend/index.html.ejs b/frontend/index.html.ejs index 09af07c6..f400a832 100644 --- a/frontend/index.html.ejs +++ b/frontend/index.html.ejs @@ -1,5 +1,5 @@ - + <%= htmlWebpackPlugin.options.title || 'Nomad UI'%> @@ -26,6 +26,7 @@ + diff --git a/frontend/src/components/Table/Table.js b/frontend/src/components/Table/Table.js index db4b338c..1abee262 100644 --- a/frontend/src/components/Table/Table.js +++ b/frontend/src/components/Table/Table.js @@ -1,3 +1,4 @@ +import React from 'react' import { Table as MaterialTable } from 'material-ui/Table' class Table extends MaterialTable { @@ -22,6 +23,13 @@ class Table extends MaterialTable { } } + render() { + return ( +
    + { Object.getPrototypeOf(Table.prototype).render.call(this) } +
    + ) + } } export default Table From 9d0299cf078b6ebecc7f6ac631a2ae6357d4cc72 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 9 Dec 2016 13:11:11 +0100 Subject: [PATCH 37/45] fix mobile version of top menu --- frontend/package.json | 17 +++- .../src/components/AppTopbar/AppTopbar.js | 71 ++++++++++---- .../src/components/AppTopbar/AppTopbar.scss | 17 ++++ .../src/components/Progressbar/Progressbar.js | 2 +- frontend/src/containers/cluster.js | 10 +- frontend/webpack-base.config.js | 49 ++++------ frontend/webpack.config.js | 97 ++++++++++--------- frontend/yarn.lock | 31 +++++- 8 files changed, 190 insertions(+), 104 deletions(-) create mode 100644 frontend/src/components/AppTopbar/AppTopbar.scss diff --git a/frontend/package.json b/frontend/package.json index 073bee06..35cd7f58 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,7 +19,17 @@ "keywords": [ "nomad" ], - "author": "Ivo Verberk", + "author": { + "name": "Christian Winther", + "email": "jippignu@gmail.com", + "url": "https://github.com/jippi" + }, + "contributors": [ + { + "name": "Ivo Verberk", + "url": "https://github.com/iverberk" + } + ], "license": "MIT ", "dependencies": { "babel-polyfill": "^6.16.0", @@ -31,12 +41,14 @@ "eslint-plugin-promise": "^3.4.0", "eslint-plugin-standard": "^2.0.1", "flexboxgrid": "^6.3.1", + "immutability-helper": "^2.0.0", "json-formatter-js": "^1.1.0", "material-ui": "^0.16.4", "moment": "^2.15.1", "moment-duration-format": "^1.3.0", "node-uuid": "^1.4.7", "react": "^15.4.1", + "react-addons-css-transition-group": "^15.4.1", "react-addons-perf": "^15.4.1", "react-addons-transition-group": "^15.4.1", "react-bootstrap": "^0.30.7", @@ -45,6 +57,7 @@ "react-redux": "^4.4.6", "react-router": "^3.0.0", "react-tap-event-plugin": "^2.0.1", + "react-toolbox": "1.3.0", "react-tooltip": "^3.1.8", "recharts": "^0.19.0", "recompose": "^0.20.2", @@ -72,7 +85,7 @@ "eslint-plugin-import": "^2.2.0", "eslint-plugin-jsx-a11y": "^3.0.1", "eslint-plugin-react": "^6.8.0", - "extract-text-webpack-plugin": "^1.0.1", + "extract-text-webpack-plugin": "1.0.1", "file-loader": "^0.9.0", "html-webpack-plugin": "^2.24.1", "html-webpack-template": "^5.4.2", diff --git a/frontend/src/components/AppTopbar/AppTopbar.js b/frontend/src/components/AppTopbar/AppTopbar.js index bf51a627..3de20d56 100644 --- a/frontend/src/components/AppTopbar/AppTopbar.js +++ b/frontend/src/components/AppTopbar/AppTopbar.js @@ -1,7 +1,8 @@ import React, { PureComponent, PropTypes } from 'react' import AppBar from 'material-ui/AppBar' import { withRouter } from 'react-router' -import { Tabs, Tab } from 'material-ui/Tabs' +import { Tab, Tabs } from 'react-toolbox/lib/tabs'; +import theme from './AppTopbar.scss'; class AppTopbar extends PureComponent { @@ -10,53 +11,85 @@ class AppTopbar extends PureComponent { this._onClick = this.handleActive.bind(this) } - handleActive (tab) { - this.props.router.push(tab.props['data-route']) + handleActive (index) { + let route = '/cluster' + + switch (index) { + case 0: + route = '/cluster'; + break; + + case 1: + route = '/jobs' + break; + + case 2: + route = '/allocations' + break; + + case 3: + route = '/evaluations' + break; + + case 4: + route = '/clients' + break; + + case 5: + route = '/servers' + break; + + default: + route = '/cluster' + } + + this.props.router.push(route) } getActiveTab () { const location = this.props.location if (location.pathname.startsWith('/cluster')) { - return 'cluster' + return 0 } if (location.pathname.startsWith('/jobs')) { - return 'jobs' + return 1 } if (location.pathname.startsWith('/allocations')) { - return 'allocations' + return 2 } if (location.pathname.startsWith('/evaluations')) { - return 'evaluations' + return 3 } if (location.pathname.startsWith('/clients')) { - return 'clients' + return 4 } if (location.pathname.startsWith('/servers')) { - return 'servers' + return 5 } - return 'cluster' + return 0 } render () { return ( -
    +
    - - - - - - - + + + + + + + + -
    + ) } } diff --git a/frontend/src/components/AppTopbar/AppTopbar.scss b/frontend/src/components/AppTopbar/AppTopbar.scss new file mode 100644 index 00000000..e2f5520e --- /dev/null +++ b/frontend/src/components/AppTopbar/AppTopbar.scss @@ -0,0 +1,17 @@ +$tab-text-inactive-color: rgba(255, 255, 255, 0.701961); + +.navigation { + height: 48px; + + .label { + color: white; + line-height: inherit; + font-size: 14px; + font-weight: 500; + padding: 0.7rem 1.2rem; + } + + .pointer { + background-color: rgb(255, 64, 129); + } +} diff --git a/frontend/src/components/Progressbar/Progressbar.js b/frontend/src/components/Progressbar/Progressbar.js index a300cd75..1b8d3bbf 100644 --- a/frontend/src/components/Progressbar/Progressbar.js +++ b/frontend/src/components/Progressbar/Progressbar.js @@ -106,7 +106,7 @@ class Progressbar extends Component { - + { this.onPieEnter(data, index) } } onMouseLeave={ (data, index) => { this.onPieLeave(data, index) } } diff --git a/frontend/src/containers/cluster.js b/frontend/src/containers/cluster.js index f5202594..071f4c46 100644 --- a/frontend/src/containers/cluster.js +++ b/frontend/src/containers/cluster.js @@ -71,19 +71,19 @@ class Cluster extends Component { return ( - + - + - + - + - + diff --git a/frontend/webpack-base.config.js b/frontend/webpack-base.config.js index 1718ce22..12d5cd8e 100644 --- a/frontend/webpack-base.config.js +++ b/frontend/webpack-base.config.js @@ -2,32 +2,25 @@ const path = require('path'); const autoprefixer = require('autoprefixer'); module.exports = { - output: { - path: path.join(__dirname, 'build/'), - publicPath: '/' - }, - resolve: { - extensions: ['', '.js', '.jsx', '.css', '.scss'] - }, - module: { - preLoaders: [ - { - test: /\.js$/, - loader: 'eslint' - } - ], - loaders: [ - { - test: /\.css$/, - loader: 'style!css?modules', - include: /flexboxgrid/ - } - ] - }, - eslint: { - useEslintrc: true - }, - postcss: function() { - return [autoprefixer]; - } + output: { + path: path.join(__dirname, 'build/'), + publicPath: '/' + }, + resolve: { + extensions: ['', '.js', '.jsx', '.css', '.scss'] + }, + module: { + preLoaders: [ + { + test: /\.js$/, + loader: 'eslint' + } + ] + }, + eslint: { + useEslintrc: true + }, + postcss: function() { + return [autoprefixer]; + } }; diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js index 49aa1180..187977a1 100644 --- a/frontend/webpack.config.js +++ b/frontend/webpack.config.js @@ -1,65 +1,66 @@ const merge = require('webpack-merge'); const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); +const ExtractTextPlugin = require('extract-text-webpack-plugin'); var webpackConfig = require("./webpack-base.config.js"); webpackConfig = merge(webpackConfig, { - output: { - filename: 'static/bundle.js' - }, + output: { + filename: 'static/bundle.js' + }, - entry: [ - 'webpack-dev-server/client?http://localhost:3333', - 'webpack/hot/only-dev-server', - 'babel-polyfill', - './src/main.js' - ], + entry: [ + 'webpack-dev-server/client?http://localhost:3333', + 'webpack/hot/only-dev-server', + 'babel-polyfill', + './src/main.js' + ], - devtool: 'cheap-module-eval-source-map', + devtool: 'cheap-module-eval-source-map', - plugins: [ - new HtmlWebpackPlugin({ - title: 'Nomad UI', - inject: false, - template: './index.html.ejs', - favicon: './assets/img/favicon.png', - appMountId: 'app' - }), - new webpack.DefinePlugin({ 'process.env.NODE_ENV': '"development"' }), - new webpack.DefinePlugin({ 'process.env.GO_PORT': process.env.GO_PORT || 3000 }), - new webpack.HotModuleReplacementPlugin() - ], + plugins: [ + new HtmlWebpackPlugin({ + title: 'Nomad UI', + inject: false, + template: './index.html.ejs', + favicon: './assets/img/favicon.png', + appMountId: 'app' + }), + new webpack.DefinePlugin({ 'process.env.NODE_ENV': '"development"' }), + new webpack.DefinePlugin({ 'process.env.GO_PORT': process.env.GO_PORT || 3000 }), + new ExtractTextPlugin('bundle.css', { allChunks: true }), + new webpack.HotModuleReplacementPlugin() + ], - devServer: { - port: 3333, - hot: true, - historyApiFallback: true, - publicPath: webpackConfig.output.publicPath - }, + devServer: { + port: 3333, + hot: true, + historyApiFallback: true, + publicPath: webpackConfig.output.publicPath + }, - module: { + module: { + loaders: [ + { + test: /(\.scss|\.css)$/, + loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss!sass') + }, + { + test: /\.jsx?$/, + exclude: /node_modules/, loaders: [ - { - test: /\.css$/, - loader: 'style!css!postcss', - exclude: /flexboxgrid/ - }, - { - test: /\.jsx?$/, - exclude: /node_modules/, - loaders: [ - 'react-hot', - 'babel?presets[]=es2015&presets[]=es2016&presets[]=react&presets[]=react-optimize&plugins[]=transform-react-inline-elements&plugins[]=syntax-trailing-function-commas&plugins[]=transform-runtime&plugins[]=transform-class-properties&plugins[]=transform-object-rest-spread' - ] - } + 'react-hot', + 'babel?presets[]=es2015&presets[]=es2016&presets[]=react&presets[]=react-optimize&plugins[]=transform-react-inline-elements&plugins[]=syntax-trailing-function-commas&plugins[]=transform-runtime&plugins[]=transform-class-properties&plugins[]=transform-object-rest-spread' ] - }, + } + ] + }, - externals: { - 'react/addons': true, - 'react/lib/ExecutionEnvironment': true, - 'react/lib/ReactContext': true - } + externals: { + 'react/addons': true, + 'react/lib/ExecutionEnvironment': true, + 'react/lib/ReactContext': true + } }); module.exports = webpackConfig; diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 88fdc89d..4be2159c 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1888,7 +1888,7 @@ extglob@^0.3.1: dependencies: is-extglob "^1.0.0" -extract-text-webpack-plugin@^1.0.1: +extract-text-webpack-plugin@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/extract-text-webpack-plugin/-/extract-text-webpack-plugin-1.0.1.tgz#c95bf3cbaac49dc96f1dc6e072549fbb654ccd2c" dependencies: @@ -2364,6 +2364,12 @@ ignore@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.0.tgz#8d88f03c3002a0ac52114db25d2c673b0bf1e435" +immutability-helper@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/immutability-helper/-/immutability-helper-2.0.0.tgz#371657666eacf96f731f9f97e5cccd920b13a5d4" + dependencies: + invariant "^2.2.0" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -3150,6 +3156,10 @@ normalize-url@^1.4.0: query-string "^4.1.0" sort-keys "^1.0.0" +normalize.css@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/normalize.css/-/normalize.css-4.2.0.tgz#21d66cc557154d4379fd1e079ec7de58a379b099" + "npmlog@0 || 1 || 2 || 3": version "3.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-3.1.2.tgz#2d46fa874337af9498a2f12bb43d8d0be4a36873" @@ -3769,6 +3779,10 @@ react-addons-create-fragment@^15.0.0: version "15.4.1" resolved "https://registry.yarnpkg.com/react-addons-create-fragment/-/react-addons-create-fragment-15.4.1.tgz#596fde66cf7f375b5dad3c36ff6efe19c0ac47e7" +react-addons-css-transition-group@^15.4.1: + version "15.4.1" + resolved "https://registry.yarnpkg.com/react-addons-css-transition-group/-/react-addons-css-transition-group-15.4.1.tgz#60b133fac5116e4009e56ab0674dc2ddcc1a18f6" + react-addons-perf@^15.4.1: version "15.4.1" resolved "https://registry.yarnpkg.com/react-addons-perf/-/react-addons-perf-15.4.1.tgz#c6dd5a7011f43cd3222f47b7cb1aebe9d4174cb0" @@ -3799,6 +3813,12 @@ react-bootstrap@^0.30.7: uncontrollable "^4.0.1" warning "^3.0.0" +react-css-themr@^1.6.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/react-css-themr/-/react-css-themr-1.6.1.tgz#928f38d96f02f28f5b00f46a0bf160ff43d91bad" + dependencies: + invariant "^2.2.1" + react-dom@^15.4.1: version "15.4.1" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.4.1.tgz#d54c913261aaedb17adc20410d029dcc18a1344a" @@ -3881,6 +3901,15 @@ react-tap-event-plugin@^2.0.1: dependencies: fbjs "^0.8.6" +react-toolbox@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/react-toolbox/-/react-toolbox-1.3.0.tgz#408f4cabb7011e51a365eeda2c223bc903aea476" + dependencies: + classnames "^2.2.5" + core-js "^2.4.0" + normalize.css "^4.2.0" + react-css-themr "^1.6.0" + react-tooltip@^3.1.8: version "3.2.2" resolved "https://registry.yarnpkg.com/react-tooltip/-/react-tooltip-3.2.2.tgz#3a599c0eabbd9eb9597aa2d72b217fd7ba358767" From 39cdbc92191435eb8a941c106f0e0343deef067f Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 9 Dec 2016 13:26:04 +0100 Subject: [PATCH 38/45] fix production build and harden Makefile --- Makefile | 20 ++++++++++++++++---- frontend/webpack-prod.config.js | 5 ++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 1e3deb15..7e396542 100644 --- a/Makefile +++ b/Makefile @@ -6,12 +6,14 @@ EXTERNAL_TOOLS=\ GOFILES_NOVENDOR = $(shell find . -type f -name '*.go' -not -path "./backend/vendor/*") +.PHONY: bootstrap bootstrap: @for tool in $(EXTERNAL_TOOLS); do \ echo "Installing $$tool" ; \ go get $$tool; \ done +.PHONY: fmt fmt: @echo "--> Running go fmt" ; @if [ -n "`go fmt ${GOFILES_NOVENDOR}`" ]; then \ @@ -19,7 +21,8 @@ fmt: exit 1; \ fi -vet: +.PHONY: vet +vet: fmt @go tool vet 2>/dev/null ; if [ $$? -eq 3 ]; then \ go get golang.org/x/tools/cmd/vet; \ fi @@ -30,29 +33,38 @@ vet: echo "and fix them if necessary before submitting the code for review."; \ fi +.PHONY: frontend frontend: @echo "=> building frontend ..." $(MAKE) -C frontend build -backend/bindata_assetfs.go: +.PHONY: backend/bindata_assetfs.go +backend/bindata_assetfs.go: frontend @echo "=> packaging assets ..." go-bindata-assetfs -prefix frontend frontend/build/... mv -f bindata_assetfs.go backend/ +.PHONY: build build: fmt vet bootstrap frontend backend/bindata_assetfs.go $(MAKE) -C backend build +.PHONY: rebuild +rebuild: + rm -f backend/bindata_assetfs.go + rm -f backend/build/nomad-ui-darwin-amd64 + $(MAKE) -j build + +.PHONY: clean clean: @echo "=> cleaning ..." $(MAKE) -C backend clean $(MAKE) -C frontend clean rm -f backend/bindata_assetfs.go +.PHONY: docker docker: @echo "=> build and push Docker image ..." @docker login -e $(DOCKER_EMAIL) -u $(DOCKER_USER) -p $(DOCKER_PASS) docker build -f Dockerfile -t iverberk/nomad-ui:$(COMMIT) . docker tag iverberk/nomad-ui:$(COMMIT) iverberk/nomad-ui:$(TAG) docker push iverberk/nomad-ui:$(TAG) - -.PHONY: docker clean build backend frontend fmt vet diff --git a/frontend/webpack-prod.config.js b/frontend/webpack-prod.config.js index 3a18a9cb..e8e0e356 100644 --- a/frontend/webpack-prod.config.js +++ b/frontend/webpack-prod.config.js @@ -21,9 +21,8 @@ webpackConfig = merge(webpackConfig, { module: { loaders: [ { - test: /\.css$/, - loader: 'style!css!postcss', - exclude: /flexboxgrid/ + test: /(\.scss|\.css)$/, + loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss!sass') }, { test: /\.jsx?$/, From 1eb59bc40cca7def2dfe5c80c6d6089f3bf64a9b Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 9 Dec 2016 14:52:35 +0100 Subject: [PATCH 39/45] improve README and add NOMAD_LOG_LEVEL --- README.md | 20 ++++--- backend/connection.go | 134 ++++++++++++++++++++++++++++-------------- backend/main.go | 48 +++++++++++---- 3 files changed, 137 insertions(+), 65 deletions(-) diff --git a/README.md b/README.md index 9a8e7cf9..4afd430b 100644 --- a/README.md +++ b/README.md @@ -25,18 +25,25 @@ Another way to run nomad-ui is through Docker. Run the following command to start a webserver that will serve the application. ``` -docker run -e NOMAD_ADDR=... -p 8000:3000 iverberk/nomad-ui:v0.3.1 +docker run -e NOMAD_ADDR=... -p 8000:3000 iverberk/nomad-ui ``` -Check the releases page on Github to see which version is current. +Check the releases page on GitHub to see which version is current. The user interface will be accessible on localhost, port `8000`. Adjust the Docker run parameters as needed. If you need to change the port that Nomad is listening on, you should do it with ```-e NOMAD_ADDR``` environment variable that contains both hostname and port. -`NOMAD_ADDR` (IP or DNS name) should point to the correct location of your Nomad server. -If you have a Node and Go environment you can also build the production version yourself. +# Configuration + +Nomad-UI can be controlled by both ENV or CLI flags as described below + +| Environment | Flag | Default | Description | +|------------------- |----------------------- |------------------------- |------------------------------------------------------------------------------------------------------ | +| `NOMAD_ADDR` | `--nomad.address` | `http://127.0.0.1:4646` | Must point to the correct location of your Nomad server. | +| `NOMAD_PORT_http` | `--web.listen-address` | `0.0.0.0:3000` | The IP + PORT to listen on | +| `NOMAD_LOG_LEVEL` | `--log.level` | `info` | Log level to use while running the nomad-ui server - (`critical`, `error`, `warning`, `notice`, `info`, `debug`) | # Try @@ -85,8 +92,3 @@ Just run ```npm install``` and ```npm start``` and start developing. Hot reloadi changes will be visible in the browser immediately. Unfortunately there are no tests yet. If you would like to contribute please open a pull-request. - -# Credits - -The awesome dashboard theme is created by [Creative Tim](www.creative-tim.com) -and can be found [here](http://www.creative-tim.com/product/light-bootstrap-dashboard-pro) diff --git a/backend/connection.go b/backend/connection.go index aa2b74c9..0e682b42 100644 --- a/backend/connection.go +++ b/backend/connection.go @@ -10,6 +10,8 @@ import ( "github.com/gorilla/websocket" "github.com/hashicorp/nomad/api" "github.com/hashicorp/nomad/command" + + uuid "github.com/satori/go.uuid" ) const ( @@ -30,21 +32,23 @@ const ( // received on the websocket and sends out actions on Nomad state changes. It // maintains a set to keep track of the running watches. type Connection struct { - socket *websocket.Conn - - hub *Hub - - receive chan *Action - send chan *Action - + ID uuid.UUID + shortId string + socket *websocket.Conn + hub *Hub + receive chan *Action + send chan *Action destroyCh chan struct{} - - watches *set.Set + watches *set.Set } // NewConnection creates a new connection. func NewConnection(hub *Hub, socket *websocket.Conn) *Connection { + connectionId := uuid.NewV4() + return &Connection{ + ID: connectionId, + shortId: fmt.Sprintf("%s", connectionId)[0:8], watches: set.New(), hub: hub, socket: socket, @@ -54,20 +58,43 @@ func NewConnection(hub *Hub, socket *websocket.Conn) *Connection { } } +func (c *Connection) Warningf(format string, args ...interface{}) { + message := fmt.Sprintf("[%s] ", c.shortId) + format + logger.Warningf(message, args...) +} + +func (c *Connection) Errorf(format string, args ...interface{}) { + message := fmt.Sprintf("[%s] ", c.shortId) + format + logger.Errorf(message, args...) +} + +func (c *Connection) Infof(format string, args ...interface{}) { + message := fmt.Sprintf("[%s] ", c.shortId) + format + logger.Infof(message, args...) +} + +func (c *Connection) Debugf(format string, args ...interface{}) { + message := fmt.Sprintf("[%s] ", c.shortId) + format + logger.Debugf(message, args...) +} + func (c *Connection) writePump() { defer func() { c.socket.Close() }() + for { action, ok := <-c.send + if !ok { if err := c.socket.WriteMessage(websocket.CloseMessage, []byte{}); err != nil { - logger.Errorf("Could not write close message to websocket: %s", err) + c.Errorf("Could not write close message to websocket: %s", err) } return } + if err := c.socket.WriteJSON(action); err != nil { - logger.Errorf("Could not write action to websocket: %s", err) + c.Errorf("Could not write action to websocket: %s", err) } } } @@ -93,7 +120,7 @@ func (c *Connection) readPump() { } func (c *Connection) process(action Action) { - logger.Infof("Processing event %s (index %d)", action.Type, action.Index) + c.Debugf("Processing event %s (index %d)", action.Type, action.Index) switch action.Type { // @@ -201,11 +228,11 @@ func (c *Connection) watchAlloc(action Action) { defer func() { c.watches.Remove(allocID) - logger.Infof("Stopped watching alloc with id: %s", allocID) + c.Infof("Stopped watching alloc with id: %s", allocID) }() c.watches.Add(allocID) - logger.Infof("Started watching alloc with id: %s", allocID) + c.Infof("Started watching alloc with id: %s", allocID) q := &api.QueryOptions{WaitIndex: 1} for { @@ -215,7 +242,7 @@ func (c *Connection) watchAlloc(action Action) { default: alloc, meta, err := c.hub.nomad.Client.Allocations().Info(allocID, q) if err != nil { - logger.Errorf("connection: unable to fetch alloc info: %s", err) + c.Errorf("connection: unable to fetch alloc info: %s", err) time.Sleep(10 * time.Second) continue } @@ -238,11 +265,11 @@ func (c *Connection) watchEval(action Action) { defer func() { c.watches.Remove(evalID) - logger.Infof("Stopped watching eval with id: %s", evalID) + c.Infof("Stopped watching eval with id: %s", evalID) }() c.watches.Add(evalID) - logger.Infof("Started watching eval with id: %s", evalID) + c.Infof("Started watching eval with id: %s", evalID) q := &api.QueryOptions{WaitIndex: 1} for { @@ -252,7 +279,7 @@ func (c *Connection) watchEval(action Action) { default: eval, meta, err := c.hub.nomad.Client.Evaluations().Info(evalID, q) if err != nil { - logger.Errorf("connection: unable to fetch eval info: %s", err) + c.Errorf("connection: unable to fetch eval info: %s", err) time.Sleep(10 * time.Second) continue } @@ -274,7 +301,7 @@ func (c *Connection) fetchMember(action Action) { memberID := action.Payload.(string) member, err := c.hub.nomad.MemberWithID(memberID) if err != nil { - logger.Errorf("websocket: unable to fetch member %q: %s", memberID, err) + c.Errorf("websocket: unable to fetch member %q: %s", memberID, err) return } @@ -286,11 +313,11 @@ func (c *Connection) watchMember(action Action) { defer func() { c.watches.Remove(memberID) - logger.Infof("Stopped watching member with id: %s", memberID) + c.Infof("Stopped watching member with id: %s", memberID) }() c.watches.Add(memberID) - logger.Infof("Started watching member with id: %s", memberID) + c.Infof("Started watching member with id: %s", memberID) for { select { @@ -299,7 +326,7 @@ func (c *Connection) watchMember(action Action) { default: member, err := c.hub.nomad.MemberWithID(memberID) if err != nil { - logger.Errorf("connection: unable to fetch member info: %s", err) + c.Errorf("connection: unable to fetch member info: %s", err) time.Sleep(10 * time.Second) continue } @@ -317,7 +344,7 @@ func (c *Connection) fetchNode(action Action) { nodeID := action.Payload.(string) node, _, err := c.hub.nomad.Client.Nodes().Info(nodeID, nil) if err != nil { - logger.Errorf("websocket: unable to fetch node %q: %s", nodeID, err) + c.Errorf("websocket: unable to fetch node %q: %s", nodeID, err) } c.send <- &Action{Type: fetchedNode, Payload: node} } @@ -327,11 +354,11 @@ func (c *Connection) watchNode(action Action) { defer func() { c.watches.Remove(nodeID) - logger.Infof("Stopped watching node with id: %s", nodeID) + c.Infof("Stopped watching node with id: %s", nodeID) }() c.watches.Add(nodeID) - logger.Infof("Started watching node with id: %s", nodeID) + c.Infof("Started watching node with id: %s", nodeID) q := &api.QueryOptions{WaitIndex: 1} for { @@ -341,7 +368,7 @@ func (c *Connection) watchNode(action Action) { default: node, meta, err := c.hub.nomad.Client.Nodes().Info(nodeID, q) if err != nil { - logger.Errorf("connection: unable to fetch node info: %s", err) + c.Errorf("connection: unable to fetch node info: %s", err) time.Sleep(10 * time.Second) continue } @@ -362,25 +389,33 @@ func (c *Connection) watchNode(action Action) { func (c *Connection) watchGenericBroadcast(watchKey string, actionEvent string, initialPayload interface{}) { defer func() { c.watches.Remove(watchKey) - logger.Infof("Stopped watching %s", watchKey) + c.Infof("Stopped watching %s", watchKey) + + // recovering from panic caused by writing to a closed channel + if recover() == nil { + return + } + + c.Warningf("Channel %s is closed. Thats sad :(", watchKey) }() + c.watches.Add(watchKey) - logger.Infof("Sending our current %s list", watchKey) + c.Debugf("Sending our current %s list", watchKey) c.send <- &Action{Type: actionEvent, Payload: initialPayload, Index: 0} - logger.Infof("Started watching %s", watchKey) + c.Debugf("Started watching %s", watchKey) for { if !c.watches.Has(watchKey) { - logger.Infof("Connection is no longer subscribed to %s", watchKey) + c.Infof("Connection is no longer subscribed to %s", watchKey) return } - logger.Infof("Waiting on %s pipe", watchKey) + c.Debugf("Waiting on %s pipe", watchKey) channelAction := <-c.hub.nomad.updateCh if channelAction.Type != actionEvent { - logger.Infof("Type mismatch: %s <> %s", channelAction.Type, actionEvent) + c.Debugf("Type mismatch: %s <> %s", channelAction.Type, actionEvent) continue } @@ -389,7 +424,7 @@ func (c *Connection) watchGenericBroadcast(watchKey string, actionEvent string, } func (c *Connection) unwatchGenericBroadcast(watchKey string) { - logger.Infof("Removing subscription for %s", watchKey) + c.Debugf("Removing subscription for %s", watchKey) c.watches.Remove(watchKey) } @@ -398,33 +433,38 @@ func (c *Connection) watchJob(action Action) { defer func() { c.watches.Remove(jobID) - logger.Infof("Stopped watching job with id: %s", jobID) + c.Infof("Stopped watching job with id: %s", jobID) }() c.watches.Add(jobID) - logger.Infof("Started watching job with id: %s", jobID) + c.Infof("Started watching job with id: %s", jobID) q := &api.QueryOptions{WaitIndex: 1} for { select { case <-c.destroyCh: return + default: job, meta, err := c.hub.nomad.Client.Jobs().Info(jobID, q) + if err != nil { - logger.Errorf("connection: unable to fetch job info: %s", err) + c.Errorf("connection: unable to fetch job info: %s", err) time.Sleep(10 * time.Second) continue } + if !c.watches.Has(jobID) { return } + c.send <- &Action{Type: fetchedJob, Payload: job, Index: meta.LastIndex} waitIndex := meta.LastIndex if q.WaitIndex > meta.LastIndex { waitIndex = q.WaitIndex } + q = &api.QueryOptions{WaitIndex: waitIndex, WaitTime: 10 * time.Second} } } @@ -433,7 +473,7 @@ func (c *Connection) watchJob(action Action) { func (c *Connection) fetchDir(action Action) { params, ok := action.Payload.(map[string]interface{}) if !ok { - logger.Errorf("Could not decode payload") + c.Errorf("Could not decode payload") return } addr := params["addr"].(string) @@ -448,14 +488,16 @@ func (c *Connection) fetchDir(action Action) { logger.Fatalf("Could not create client: %s", err) return } + alloc, _, err := client.Allocations().Info(allocID, nil) if err != nil { - logger.Errorf("Unable to fetch alloc: %s", err) + c.Errorf("Unable to fetch alloc: %s", err) return } + dir, _, err := client.AllocFS().List(alloc, path, nil) if err != nil { - logger.Errorf("Unable to fetch directory: %s", err) + c.Errorf("Unable to fetch directory: %s", err) } c.send <- &Action{Type: fetchedDir, Payload: dir, Index: 0} @@ -481,25 +523,27 @@ func (c *Connection) watchFile(action Action) { client, err := api.NewClient(config) if err != nil { - logger.Errorf("Could not create client: %s", err) + c.Errorf("Could not create client: %s", err) return } + alloc, _, err := client.Allocations().Info(allocID, nil) if err != nil { - logger.Errorf("Unable to fetch alloc: %s", err) + c.Errorf("Unable to fetch alloc: %s", err) return } // Get file stat info file, _, err := client.AllocFS().Stat(alloc, path, nil) if err != nil { - logger.Errorf("Unable to stat file: %s", err) + c.Errorf("Unable to stat file: %s", err) return } var origin string = api.OriginStart var offset int64 = 0 var oversized bool + if file.Size > maxFileSize { origin = api.OriginEnd offset = maxFileSize @@ -519,7 +563,7 @@ func (c *Connection) watchFile(action Action) { Index: 0, } - logger.Errorf("Unable to stream file: %s", err) + c.Errorf("Unable to stream file: %s", err) return } @@ -545,12 +589,12 @@ func (c *Connection) watchFile(action Action) { c.watches.Add(path) defer func() { - logger.Infof("Stopped watching file with path: %s", path) + c.Infof("Stopped watching file with path: %s", path) c.watches.Remove(path) r.Close() }() - logger.Infof("Started watching file with path: %s", path) + c.Infof("Started watching file with path: %s", path) c.send <- &Action{ Type: fetchedFile, Payload: struct { diff --git a/backend/main.go b/backend/main.go index 5550f186..2a8c0e9b 100644 --- a/backend/main.go +++ b/backend/main.go @@ -6,7 +6,7 @@ import ( "os" "syscall" "time" - + "strings" "net/http" "github.com/gorilla/mux" @@ -15,16 +15,23 @@ import ( var logger = logging.MustGetLogger("nomad-ui") -func init() { +func startLogging(logLevel string) { logBackend := logging.NewLogBackend(os.Stderr, "", 0) format := logging.MustStringFormatter( - `%{color}%{time:15:04:05.000} %{shortfile} ▶ %{level:.4s} %{color:reset} %{message}`, + `%{color}%{time:15:04:05.000} %{shortfile} ▶ %{level:.5s} %{color:reset} %{message}`, ) logBackendFormatted := logging.NewBackendFormatter(logBackend, format) logBackendFormattedAndLeveled := logging.AddModuleLevel(logBackendFormatted) - logBackendFormattedAndLeveled.SetLevel(logging.INFO, "") + + realLogLevel, err := logging.LogLevel(strings.ToUpper(logLevel)) + if err != nil { + fmt.Printf("%s (%s)", err, logLevel) + os.Exit(1) + } + + logBackendFormattedAndLeveled.SetLevel(realLogLevel, "") logging.SetBackend(logBackendFormattedAndLeveled) } @@ -32,12 +39,14 @@ func init() { type Config struct { Address string ListenAddress string + LogLevel string } func DefaultConfig() *Config { return &Config{ Address: "http://127.0.0.1:4646", ListenAddress: "0.0.0.0:3000", + LogLevel: "info", } } @@ -48,10 +57,14 @@ func flagDefault(value string) string { var ( defaultConfig = DefaultConfig() - flagAddress = flag.String("address", "", "The address of the Nomad server. "+ + flagAddress = flag.String("nomad.address", "", "The address of the Nomad server. "+ "Overrides the NOMAD_ADDR environment variable if set. "+flagDefault(defaultConfig.Address)) + flagListenAddress = flag.String("web.listen-address", "", "The address on which to expose the web interface. "+flagDefault(defaultConfig.ListenAddress)) + + flagLogLevel = flag.String("log.level", "", + "The log level for nomad-ui to run under. "+flagDefault(defaultConfig.LogLevel)) ) func (c *Config) Parse() { @@ -67,6 +80,11 @@ func (c *Config) Parse() { c.ListenAddress = fmt.Sprintf("0.0.0.0:%s", listenPort) } + logLevel, ok := syscall.Getenv("NOMAD_LOG_LEVEL") + if ok { + c.LogLevel = logLevel + } + if *flagAddress != "" { c.Address = *flagAddress } @@ -74,17 +92,25 @@ func (c *Config) Parse() { if *flagListenAddress != "" { c.ListenAddress = *flagListenAddress } + + if *flagLogLevel != "" { + c.LogLevel = *flagLogLevel + } } func main() { cfg := DefaultConfig() cfg.Parse() - logger.Infof("----------------------------------------------------------------------") - logger.Infof("| NOMAD UI |") - logger.Infof("----------------------------------------------------------------------") - logger.Infof("| address : %-45s |", cfg.Address) - logger.Infof("| web.listen-address : %-45s |", cfg.ListenAddress) - logger.Infof("----------------------------------------------------------------------") + + startLogging(cfg.LogLevel) + + logger.Infof("---------------------------------------------------------------------------") + logger.Infof("| NOMAD UI |") + logger.Infof("---------------------------------------------------------------------------") + logger.Infof("| nomad.address : %-50s |", cfg.Address) + logger.Infof("| web.listen-address : http://%-43s |", cfg.ListenAddress) + logger.Infof("| log.level : %-50s |", cfg.LogLevel) + logger.Infof("---------------------------------------------------------------------------") logger.Infof("") broadcast := make(chan *Action) From e883e8564693e479ddc404b75cecfeab3fb8183f Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 9 Dec 2016 14:55:09 +0100 Subject: [PATCH 40/45] Restyle cluster --- frontend/src/containers/cluster.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/frontend/src/containers/cluster.js b/frontend/src/containers/cluster.js index 071f4c46..fbd9996f 100644 --- a/frontend/src/containers/cluster.js +++ b/frontend/src/containers/cluster.js @@ -71,22 +71,24 @@ class Cluster extends Component { return ( - - - - - - - + - + - + + + + + + + + + From 7fb257d03e04923032bfb56b9f53a868ff70d627 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 9 Dec 2016 14:57:49 +0100 Subject: [PATCH 41/45] cluster charts can be clicked to toggle labels --- frontend/src/components/Progressbar/Progressbar.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/src/components/Progressbar/Progressbar.js b/frontend/src/components/Progressbar/Progressbar.js index 1b8d3bbf..7c95c561 100644 --- a/frontend/src/components/Progressbar/Progressbar.js +++ b/frontend/src/components/Progressbar/Progressbar.js @@ -22,6 +22,10 @@ class Progressbar extends Component { this.setState({ showLabel: true }) } + onPieClick() { + this.setState({ showLabel: !this.state.showLabel }) + } + renderActiveShape(props) { const { cx, cy, innerRadius, outerRadius, startAngle, endAngle, fill, payload, percent } = props; const p = (percent * 100).toFixed(0) @@ -110,6 +114,7 @@ class Progressbar extends Component { { this.onPieEnter(data, index) } } onMouseLeave={ (data, index) => { this.onPieLeave(data, index) } } + onClick={ (data, index) => { this.onPieClick(data, index) } } > Date: Fri, 9 Dec 2016 15:10:05 +0100 Subject: [PATCH 42/45] rework frontend css --- backend/main.go | 4 ++-- frontend/assets/nomad-ui.css | 2 +- frontend/src/components/Table/Table.js | 2 +- frontend/src/main.js | 9 +++++---- frontend/webpack-prod.config.js | 6 +++++- frontend/webpack.config.js | 6 +++++- 6 files changed, 19 insertions(+), 10 deletions(-) diff --git a/backend/main.go b/backend/main.go index 2a8c0e9b..ef713928 100644 --- a/backend/main.go +++ b/backend/main.go @@ -3,11 +3,11 @@ package main import ( "flag" "fmt" + "net/http" "os" + "strings" "syscall" "time" - "strings" - "net/http" "github.com/gorilla/mux" "github.com/op/go-logging" diff --git a/frontend/assets/nomad-ui.css b/frontend/assets/nomad-ui.css index 0dbf9f7f..8d467892 100644 --- a/frontend/assets/nomad-ui.css +++ b/frontend/assets/nomad-ui.css @@ -68,7 +68,7 @@ th { text-align: left } -.table-responsive { +.nomad-table-responsive { border: 0; width: 100%; margin-bottom: 15px; diff --git a/frontend/src/components/Table/Table.js b/frontend/src/components/Table/Table.js index 1abee262..f58c5a89 100644 --- a/frontend/src/components/Table/Table.js +++ b/frontend/src/components/Table/Table.js @@ -25,7 +25,7 @@ class Table extends MaterialTable { render() { return ( -
    +
    { Object.getPrototypeOf(Table.prototype).render.call(this) }
    ) diff --git a/frontend/src/main.js b/frontend/src/main.js index 1ec29379..8f3ce1f0 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -3,13 +3,14 @@ import ReactDOM from 'react-dom' import { browserHistory } from 'react-router' import { Provider } from 'react-redux' -import Perf from 'react-addons-perf' -import '../assets/nomad-ui.css' +// import Perf from 'react-addons-perf' import AppRouter from './router' import configureStore from './store' -Perf.start() +import '../assets/nomad-ui.css' + +// Perf.start() configureStore().then((store) => { ReactDOM.render( @@ -22,4 +23,4 @@ configureStore().then((store) => { console.log(err) }) -window.Perf = Perf +// window.Perf = Perf diff --git a/frontend/webpack-prod.config.js b/frontend/webpack-prod.config.js index e8e0e356..8b390449 100644 --- a/frontend/webpack-prod.config.js +++ b/frontend/webpack-prod.config.js @@ -21,9 +21,13 @@ webpackConfig = merge(webpackConfig, { module: { loaders: [ { - test: /(\.scss|\.css)$/, + test: /(\.scss)$/, loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss!sass') }, + { + test: /\.css$/, + loader: ExtractTextPlugin.extract('style', 'css!postcss') + }, { test: /\.jsx?$/, exclude: /node_modules/, diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js index 187977a1..a461b382 100644 --- a/frontend/webpack.config.js +++ b/frontend/webpack.config.js @@ -42,9 +42,13 @@ webpackConfig = merge(webpackConfig, { module: { loaders: [ { - test: /(\.scss|\.css)$/, + test: /(\.scss)$/, loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss!sass') }, + { + test: /\.css$/, + loader: ExtractTextPlugin.extract('style', 'css!postcss') + }, { test: /\.jsx?$/, exclude: /node_modules/, From 2968cc82feed493756b0e41a91547ef4780b20c5 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 9 Dec 2016 15:31:38 +0100 Subject: [PATCH 43/45] fix css loading, somehow --- frontend/webpack-prod.config.js | 15 +++++++++++---- frontend/webpack.config.js | 14 +++++++++++--- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/frontend/webpack-prod.config.js b/frontend/webpack-prod.config.js index 8b390449..e6f3983f 100644 --- a/frontend/webpack-prod.config.js +++ b/frontend/webpack-prod.config.js @@ -21,18 +21,25 @@ webpackConfig = merge(webpackConfig, { module: { loaders: [ { - test: /(\.scss)$/, - loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss!sass') + test: /\.scss$/, + exclude: /flexboxgrid/, + loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss!sass'), }, { test: /\.css$/, - loader: ExtractTextPlugin.extract('style', 'css!postcss') + include: /flexboxgrid/, + loader: ExtractTextPlugin.extract('style', 'css'), + }, + { + test: /\.css$/, + exclude: /flexboxgrid/, + loader: ExtractTextPlugin.extract('style', 'css!postcss'), }, { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel', - query: require('./config/babel.prod') + query: require('./config/babel.prod'), } ] }, diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js index a461b382..23a83e2d 100644 --- a/frontend/webpack.config.js +++ b/frontend/webpack.config.js @@ -42,12 +42,20 @@ webpackConfig = merge(webpackConfig, { module: { loaders: [ { - test: /(\.scss)$/, - loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss!sass') + test: /(\.scss|\.css)$/, + loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss!sass'), + exclude: /flexboxgrid|assets/, }, { test: /\.css$/, - loader: ExtractTextPlugin.extract('style', 'css!postcss') + loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'), + include: /flexboxgrid/, + exclude: /assets/, + }, + { + test: /\.css$/, + loader: ExtractTextPlugin.extract('style', 'css?importLoaders=1'), + include: /assets/, }, { test: /\.jsx?$/, From 2c338c2273572d4bd6259905def8d4820387eef0 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 9 Dec 2016 15:55:08 +0100 Subject: [PATCH 44/45] fix prod style config --- frontend/webpack-prod.config.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/frontend/webpack-prod.config.js b/frontend/webpack-prod.config.js index e6f3983f..e05c6e2e 100644 --- a/frontend/webpack-prod.config.js +++ b/frontend/webpack-prod.config.js @@ -21,19 +21,20 @@ webpackConfig = merge(webpackConfig, { module: { loaders: [ { - test: /\.scss$/, - exclude: /flexboxgrid/, + test: /(\.scss|\.css)$/, loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss!sass'), + exclude: /flexboxgrid|assets/, }, { test: /\.css$/, + loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'), include: /flexboxgrid/, - loader: ExtractTextPlugin.extract('style', 'css'), + exclude: /assets/, }, { test: /\.css$/, - exclude: /flexboxgrid/, - loader: ExtractTextPlugin.extract('style', 'css!postcss'), + loader: ExtractTextPlugin.extract('style', 'css?importLoaders=1'), + include: /assets/, }, { test: /\.jsx?$/, From 28ceb8de197763138ba581e4d9d2d9a517fa9892 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Fri, 9 Dec 2016 16:25:06 +0100 Subject: [PATCH 45/45] update screenshots --- README.md | 8 +++--- SCREENSHOTS.md | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 SCREENSHOTS.md diff --git a/README.md b/README.md index 4afd430b..86844295 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,11 @@ Nomad UI [![Build Status](https://travis-ci.org/iverberk/nomad-ui.svg?branch=mas [![Join the chat at https://gitter.im/nomad-ui/Lobby](https://badges.gitter.im/nomad-ui/Lobby.svg)](https://gitter.im/nomad-ui/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -An awesome user interface for an awesome scheduler, plain and simple :-) +An awesome user interface (even for mobile devices!) for an awesome scheduler, plain and simple :-) -![Nomad UI](http://www.ivoverberk.nl/dl/nomad-ui.jpg) -![Nomad UI](http://www.ivoverberk.nl/dl/nomad-ui-2.jpg) -![Nomad UI](http://www.ivoverberk.nl/dl/nomad-ui-3.jpg) +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/cluster-overview-small.jpg) + +[More screenshots](https://github.com/iverberk/nomad-ui/blob/master/SCREENSHOTS.md) # Usage diff --git a/SCREENSHOTS.md b/SCREENSHOTS.md new file mode 100644 index 00000000..6933ff6b --- /dev/null +++ b/SCREENSHOTS.md @@ -0,0 +1,72 @@ +# Cluster + +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/cluster-overview.jpg) + +# Jobs + +## List + +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/job-list.jpg) +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/job-list-filter.jpg) + +### Mobile + +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/job-list-mobile.jpg) + +## Details + +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/job-details-info.jpg) +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/job-details-allocations.jpg) +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/job-details-evaluations.jpg) +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/job-details-task-groups.jpg) +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/job-details-raw.jpg) + +# Allocations + +## List + +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/allocation-list-filtered.jpg) +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/allocation-list.jpg) + +## Details + +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/allocation-details-info.jpg) +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/allocation-details-files.jpg) +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/allocation-details-logs.jpg) +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/allocation-details-raw.jpg) + +# Client + +## List + +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/client-list.jpg) + +## Details + +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/client-details-info.jpg) +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/client-details-allocations.jpg) +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/client-details-evaluations.jpg) +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/client-details-raw.jpg) + +# Evaluation + +## List + +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/evaluation-list.jpg) + +## Details + +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/evaluation-details-info.jpg) +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/evaluation-details-allocations.jpg) +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/evaluation-details-raw.jpg) + +# Server + +## List + +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/server-list.jpg) + +## Details + +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/server-details-info.jpg) +![Nomad UI](https://dl.dropboxusercontent.com/u/27514/nomad-screenshots/0.5/server-details-raw.jpg)