| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625 |
- ## Licensed to Cloudera, Inc. under one
- ## or more contributor license agreements. See the NOTICE file
- ## distributed with this work for additional information
- ## regarding copyright ownership. Cloudera, Inc. licenses this file
- ## to you under the Apache License, Version 2.0 (the
- ## "License"); you may not use this file except in compliance
- ## with the License. You may obtain a copy of the License at
- ##
- ## http://www.apache.org/licenses/LICENSE-2.0
- ##
- ## Unless required by applicable law or agreed to in writing, software
- ## distributed under the License is distributed on an "AS IS" BASIS,
- ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ## See the License for the specific language governing permissions and
- ## limitations under the License.
- <%
- from desktop import conf
- from desktop.views import commonheader, commonfooter, _ko
- from django.utils.translation import ugettext as _
- %>
- % if not is_embeddable:
- ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
- <%namespace name="assist" file="/assist.mako" />
- % endif
- <span class="notebook">
- <link rel="stylesheet" href="${ static('desktop/ext/css/basictable.css') }">
- <link rel="stylesheet" href="${ static('notebook/css/notebook.css') }">
- % if not is_embeddable:
- <link rel="stylesheet" href="${ static('notebook/css/notebook-layout.css') }">
- <style type="text/css">
- % if conf.CUSTOM.BANNER_TOP_HTML.get():
- .show-assist {
- top: 110px!important;
- }
- .main-content {
- top: 112px!important;
- }
- % endif
- </style>
- % endif
- <script src="${ static('oozie/js/dashboard-utils.js') }" type="text/javascript" charset="utf-8"></script>
- <script src="${ static('desktop/ext/js/jquery/plugins/jquery.basictable.min.js') }"></script>
- <script src="${ static('desktop/ext/js/jquery/plugins/jquery-ui-1.10.4.custom.min.js') }"></script>
- <script src="${ static('desktop/js/apiHelper.js') }"></script>
- <script src="${ static('desktop/js/ko.charts.js') }"></script>
- <script src="${ static('desktop/ext/js/knockout-sortable.min.js') }"></script>
- <script src="${ static('desktop/js/ko.editable.js') }"></script>
- <script src="${ static('oozie/js/list-oozie-coordinator.ko.js') }"></script>
- % if not is_embeddable:
- ${ assist.assistJSModels() }
- ${ assist.assistPanel() }
- <a title="${_('Toggle Assist')}" class="pointer show-assist" data-bind="visible: !$root.isLeftPanelVisible() && $root.assistAvailable(), click: function() { $root.isLeftPanelVisible(true); }">
- <i class="fa fa-chevron-right"></i>
- </a>
- % endif
- <div id="jobbrowserComponents">
- <div class="navbar navbar-inverse navbar-fixed-top nokids">
- <div class="navbar-inner">
- <div class="container-fluid">
- <div class="nav-collapse">
- <ul class="nav">
- <li class="currentApp">
- <a href="/${app_name}">
- <img src="${ static('jobbrowser/art/icon_jobbrowser_48.png') }" class="app-icon"/>
- ${ _('Job Browser') }
- </a>
- </li>
- </ul>
- <span class="form-inline">
- <input class="btn btn-status" type="radio" name="interface" value="apps" data-bind="checked: interface" id="apps"><label for="apps">${ _('Apps') }</label>
- <input class="btn btn-status" type="radio" name="interface" value="workflows" data-bind="checked: interface" id="workflows"><label for="workflows">${ _('Workflows') }</label>
- <input class="btn btn-status" type="radio" name="interface" value="schedules" data-bind="checked: interface" id="schedules"><label for="schedules">${ _('Schedules') }</label>
- <input class="btn btn-status" type="radio" name="interface" value="bundles" data-bind="checked: interface" id="bundles"><label for="bundles">${ _('Bundles') }</label>
- </span>
- % if not hiveserver2_impersonation_enabled:
- <div class="pull-right alert alert-warning" style="margin-top: 4px">${ _("Hive jobs are running as the 'hive' user") }</div>
- % endif
- </div>
- </div>
- </div>
- </div>
- <div class="main-content">
- <div class="vertical-full container-fluid" data-bind="style: { 'padding-left' : $root.isLeftPanelVisible() ? '0' : '20px' }">
- <div class="vertical-full">
- <div class="vertical-full row-fluid panel-container">
- % if not is_embeddable:
- <div class="assist-container left-panel" data-bind="visible: $root.isLeftPanelVisible() && $root.assistAvailable()">
- <a title="${_('Toggle Assist')}" class="pointer hide-assist" data-bind="click: function() { $root.isLeftPanelVisible(false) }">
- <i class="fa fa-chevron-left"></i>
- </a>
- <div class="assist" data-bind="component: {
- name: 'assist-panel',
- params: {
- user: '${user.username}',
- sql: {
- sourceTypes: [{
- name: 'hive',
- type: 'hive'
- }],
- navigationSettings: {
- openItem: false,
- showStats: true
- }
- },
- visibleAssistPanels: ['sql']
- }
- }"></div>
- </div>
- <div class="resizer" data-bind="visible: $root.isLeftPanelVisible() && $root.assistAvailable(), splitDraggable : { appName: 'notebook', leftPanelVisible: $root.isLeftPanelVisible }"><div class="resize-bar"> </div></div>
- % endif
- <div class="content-panel">
- <div class="container-fluid">
- <div data-bind="template: { name: 'breadcrumbs' }"></div>
- <!-- ko if: ! $root.job() -->
- ${_('Filter')} <input id="textFilter" type="text" class="input-xlarge search-query" placeholder="${_('Filter by id, name, user...')}" value="user:${ user.username }">
- <span class="btn-group">
- <class="btn-group">
- <a class="btn btn-status btn-success" data-value="completed">${ _('Succeeded') }</a>
- <a class="btn btn-status btn-warning" data-value="running">${ _('Running') }</a>
- <a class="btn btn-status btn-danger disable-feedback" data-value="failed">${ _('Failed') }</a>
- </span>
- </span>
- <div class="btn-toolbar pull-right" style="display: inline; vertical-align: middle; margin-left: 10px; font-size: 12px">
- <span class="loader hide"><i class="fa fa-2x fa-spinner fa-spin muted"></i></span>
- <button class="btn bulkToolbarBtn bulk-resume" data-operation="resume" title="${ _('Resume selected') }" disabled="disabled" type="button"><i class="fa fa-play"></i><span class="hide-small"> ${ _('Resume') }</span></button>
- <button class="btn bulkToolbarBtn bulk-suspend" data-operation="suspend" title="${ _('Suspend selected') }" disabled="disabled" type="button"><i class="fa fa-pause"></i><span class="hide-small"> ${ _('Suspend') }</span></button>
- <button class="btn bulkToolbarBtn btn-danger bulk-kill disable-feedback" data-operation="kill" title="${ _('Kill selected') }" disabled="disabled" type="button"><i class="fa fa-times"></i><span class="hide-small"> ${ _('Kill') }</span></button>
- </div>
- <div class="card card-small">
- <table id="jobsTable" class="datatables table table-condensed">
- <thead>
- <tr>
- <th width="1%"><div class="select-all hueCheckbox fa"></div></th>
- <th>${_('Duration')}</th>
- <th>${_('Type')}</th>
- <th>${_('Status')}</th>
- <th>${_('Progress')}</th>
- <th>${_('Name')}</th>
- <th>${_('User')}</th>
- <th>${_('Id')}</th>
- </tr>
- </thead>
- <tbody data-bind="foreach: jobs.apps">
- <tr data-bind="click: fetchJob">
- <td><div class="hueCheckbox fa"></div></td>
- <td data-bind="text: duration"></td>
- <td data-bind="text: type"></td>
- <td data-bind="text: status"></td>
- <td data-bind="text: progress"></td>
- <td data-bind="text: name"></td>
- <td data-bind="text: user"></td>
- <td data-bind="text: id"></td>
- </tr>
- </tbody>
- </table>
- </div>
- <!-- /ko -->
- </div>
- <!-- ko if: $root.job() -->
- <!-- ko if: $root.job().mainType() == 'apps' -->
- <div data-bind="template: { name: 'job-page', data: $root.job() }"></div>
- <!-- /ko -->
- <!-- ko if: $root.job().mainType() == 'workflows' -->
- <div data-bind="template: { name: 'workflow-page', data: $root.job() }"></div>
- <!-- /ko -->
- <!-- ko if: $root.job().mainType() == 'schedules' -->
- <div data-bind="template: { name: 'schedule-page', data: $root.job() }"></div>
- <!-- /ko -->
- <!-- /ko -->
- <div data-bind="template: { name: 'pagination' }, visible: ! $root.job()"></div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <script type="text/html" id="breadcrumbs">
-
- <h2 data-bind="foreach: breadcrumbs">
- <!-- ko if: $index() > 0 -->
- >
- <!-- /ko -->
-
- ## TODO: no link on last item
- <!-- ko if: id.length == 0 -->
- <span data-bind="text: name, click: function() { $root.interface(name); $parent.breadcrumbs([{'id': '', 'name': name, 'type': type}]); $root.job(null); }"></span>
- <!-- /ko -->
- <!-- ko if: id.length != 0 -->
- <span data-bind="text: type, click: function() { $parent.breadcrumbs.splice($index()); $root.job().fetchJob(id); }"></span>
- :
- <span data-bind="text: id, click: function() { $parent.breadcrumbs.splice($index()); $root.job().fetchJob(id); }"></span>
- <!-- /ko -->
- </h2>
- </script>
- <script type="text/html" id="pagination">
- Showing
- <span data-bind="text: paginationPage"></span>
- to
- <span data-bind="text: paginationOffset() * paginationResultPage()"></span>
- of
- <span data-bind="text: paginationResultCounts"></span>
-
- Show
- <span data-bind="text: paginationOffset"></span>
- results by page.
- </script>
- <script type="text/html" id="job-page">
- <!-- ko if: type() == 'MAPREDUCE' -->
- <div data-bind="template: { name: 'job-mapreduce-page', data: $root.job() }"></div>
- <!-- /ko -->
- <!-- ko if: type() == 'YARN' -->
- <div data-bind="template: { name: 'job-yarn-page', data: $root.job() }"></div>
- <!-- /ko -->
- <!-- ko if: type() == 'IMPALA' -->
- <div data-bind="template: { name: 'job-impala-page', data: $root.job() }"></div>
- <!-- /ko -->
- <!-- ko if: type() == 'SPARK' -->
- <div data-bind="template: { name: 'job-spark-page', data: $root.job() }"></div>
- <!-- /ko -->
- </script>
- <script type="text/html" id="job-yarn-page">
- <h2>YARN</h2>
- <br/>
- ${ _('Id') } <span data-bind="text: id"></span>
- ${ _('Name') } <span data-bind="text: name"></span>
- ${ _('Type') } <span data-bind="text: type"></span>
- ${ _('Status') } <span data-bind="text: status"></span>
- ${ _('User') } <span data-bind="text: user"></span>
- ${ _('Progress') } <span data-bind="text: progress"></span>
- ${ _('Duration') } <span data-bind="text: duration"></span>
- ${ _('Submitted') } <span data-bind="text: submitted"></span>
- </script>
- <script type="text/html" id="job-mapreduce-page">
- ${ _('Id') } <span data-bind="text: id"></span>
- ${ _('Name') } <span data-bind="text: name"></span>
- ${ _('Type') } <span data-bind="text: type"></span>
- ${ _('Status') } <span data-bind="text: status"></span>
- ${ _('User') } <span data-bind="text: user"></span>
- ${ _('Progress') } <span data-bind="text: progress"></span>
- ${ _('Duration') } <span data-bind="text: duration"></span>
- ${ _('Submitted') } <span data-bind="text: submitted"></span>
- </br></br>
-
- <!-- ko with: properties -->
- Map <span data-bind="text: maps_percent_complete"></span> <span data-bind="text: finishedMaps"></span> /<span data-bind="text: desiredMaps"></span>
- Reduce <span data-bind="text: reduces_percent_complete"></span> <span data-bind="text: finishedReduces"></span> / <span data-bind="text: desiredReduces"></span><br/>
- Duration <span data-bind="text: $parent.duration"></span><br/>
- <!-- /ko -->
- </br></br>
- <div class="progress-job progress active pull-left" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-warning': progress() < 100, 'progress-success': progress() === 100}">
- <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
- </div>
- Stop
- </br>
- <ul class="nav nav-tabs">
- <li class="active"><a href="#job-mapreduce-page-logs" data-toggle="tab">${ _('Logs') }</a></li>
- <li><a href="#job-mapreduce-page-attempts" data-toggle="tab">${ _('Attempts') }</a></li>
- <li><a href="#job-mapreduce-page-tasks" data-toggle="tab">${ _('Tasks') }</a></li>
- <li><a href="#job-mapreduce-page-metadata" data-toggle="tab">${ _('Metadata') }</a></li>
- <li><a href="#job-mapreduce-page-counters" data-toggle="tab">${ _('Counters') }</a></li>
- </ul>
- <div class="tab-content active" id="job-mapreduce-page-logs">
- % for name in ['stdout', 'stderr', 'syslog']:
- <a href="javascript:void(0)" data-bind="click: fetchLogs, text: '${ name }'"></a>
- % endfor
- </br>
- <pre data-bind="html: logs['default']"></pre>
- </div>
- <div class="tab-content" id="job-mapreduce-page-attempts">
- <table class="table table-condensed">
- </table>
- </div>
- <div class="tab-content" id="job-mapreduce-page-tasks">
- <table class="table table-condensed">
- </table>
- </div>
-
- <div class="tab-content" id="job-mapreduce-page-metadata">
- <table class="table table-condensed">
- </table>
- </div>
-
- <div class="tab-content" id="job-mapreduce-page-counters">
- <table class="table table-condensed">
- </table>
- </div>
- </script>
- <script type="text/html" id="job-mapreduce-task-page">
- <h2>MapReduce Task</h2>
- <br/>
-
- Task Attemps | Metadata | Counters
- </script>
- <script type="text/html" id="job-mapreduce-task-attempt-page">
- <h2>MapReduce Task attempt</h2>
- <br/>
-
- Container | Metadata | Counters
- </script>
- <script type="text/html" id="job-impala-page">
- <h2>Impala</h2>
- <br/>
- ${ _('Id') } <span data-bind="text: id"></span>
- ${ _('Name') } <span data-bind="text: name"></span>
- ${ _('Type') } <span data-bind="text: type"></span>
- ${ _('Status') } <span data-bind="text: status"></span>
- ${ _('User') } <span data-bind="text: user"></span>
- ${ _('Progress') } <span data-bind="text: progress"></span>
- ${ _('Duration') } <span data-bind="text: duration"></span>
- ${ _('Submitted') } <span data-bind="text: submitted"></span>
- </script>
- <script type="text/html" id="job-spark-page">
- ${ _('Id') } <span data-bind="text: id"></span>
- ${ _('Name') } <span data-bind="text: name"></span>
- ${ _('Type') } <span data-bind="text: type"></span>
- ${ _('Status') } <span data-bind="text: status"></span>
- ${ _('User') } <span data-bind="text: user"></span>
- ${ _('Progress') } <span data-bind="text: progress"></span>
- ${ _('Duration') } <span data-bind="text: duration"></span>
- ${ _('Submitted') } <span data-bind="text: submitted"></span>
- </script>
- <script type="text/html" id="workflow-page">
- ${ _('Id') } <span data-bind="text: id"></span>
- ${ _('Name') } <span data-bind="text: name"></span>
- ${ _('Type') } <span data-bind="text: type"></span>
- ${ _('Status') } <span data-bind="text: status"></span>
- ${ _('User') } <span data-bind="text: user"></span>
- ${ _('Progress') } <span data-bind="text: progress"></span>
- ${ _('Duration') } <span data-bind="text: duration"></span>
- ${ _('Submitted') } <span data-bind="text: submitted"></span>
-
- </br></br>
- Variables</br>
- Duration 8s</br>
- </br></br>
-
- <div class="progress-job progress active pull-left" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-warning': progress() < 100, 'progress-success': progress() === 100}">
- <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
- </div>
- Stop | Resume
- <br/>
- <ul class="nav nav-tabs">
- <li class="active"><a href="#workflow-page-graph" data-toggle="tab">${ _('Graph') }</a></li>
- <li><a href="#workflow-page-logs" data-toggle="tab">${ _('Logs') }</a></li>
- <li><a href="#workflow-page-tasks" data-toggle="tab">${ _('Tasks') }</a></li>
- <li><a href="#workflow-page-metadata" data-toggle="tab">${ _('Metadata') }</a></li>
- </ul>
- <div class="tab-content active" id="workflow-page-graph">
- <span data-bind="html: properties().graph"></span>
- </div>
- <div class="tab-content" id="workflow-page-logs">
- <pre data-bind="html: logs['default']"></pre>
- </div>
- <div class="tab-content" id="workflow-page-tasks">
- <table class="table table-condensed">
- </table>
- </div>
-
- <div class="tab-content" id="workflow-page-metadata">
- <table class="table table-condensed">
- </table>
- </div>
- </script>
- <script type="text/html" id="schedule-page">
- ${ _('Id') } <span data-bind="text: id"></span>
- ${ _('Name') } <span data-bind="text: name"></span>
- ${ _('Type') } <span data-bind="text: type"></span>
- ${ _('Status') } <span data-bind="text: status"></span>
- ${ _('User') } <span data-bind="text: user"></span>
- ${ _('Progress') } <span data-bind="text: progress"></span>
- ${ _('Duration') } <span data-bind="text: duration"></span>
- ${ _('Submitted') } <span data-bind="text: submitted"></span>
- <!-- ko with: coordVM -->
- <div>
- <table class="table table-striped table-condensed margin-top-10">
- <tbody data-bind="foreach: filteredActions">
- <tr data-bind="css: { disabled: url == '' }">
- <td data-bind="css: { disabled: url == '' }">
- <a data-bind="attr: {href: url != '' ? url : 'javascript:void(0)', title: url ? '' : '${ _ko('Workflow not available or instantiated yet') }' }, css: { disabled: url == '' }" target="_blank">
- <span data-bind="text: title, attr: {'class': statusClass, 'id': 'date-' + $index()}"></span>
- </a>
- <span class="pull-right">
- <i class="fa fa-exclamation-triangle" data-bind="visible: (errorMessage == null || errorMessage == '') && (missingDependencies == null || missingDependencies == '') && url == '', attr: {title: '${ _ko('Workflow not available or instantiated yet') }'}"></i><i class="fa fa-exclamation-triangle" data-bind="visible: errorMessage != null && errorMessage != '', attr: {title: errorMessage}"></i> <i class="fa fa-exclamation-triangle" data-bind="visible:missingDependencies !='' && missingDependencies != null, attr: { title: '${ _ko('Missing')} ' + missingDependencies }"></i>
- </span>
- </td>
- </tr>
- </tbody>
- <tfoot>
- <tr data-bind="visible: filteredActions().length == 0">
- <td>
- <div class="alert">
- ${ _('There are no actions to be shown.') }
- </div>
- </td>
- </tr>
- </tfoot>
- </table>
- </div>
- <!-- /ko -->
- </div>
- </script>
- <script type="text/javascript" charset="utf-8">
- (function () {
- var Job = function (vm, job) {
- var self = this;
- self.id = ko.observableDefault(job.id);
- self.name = ko.observableDefault(job.name);
- self.type = ko.observableDefault(job.type);
- self.status = ko.observableDefault(job.status);
- self.user = ko.observableDefault(job.user);
- self.cluster = ko.observableDefault(job.cluster);
- self.progress = ko.observableDefault(job.progress);
- self.duration = ko.observableDefault(job.duration);
- self.submitted = ko.observableDefault(job.submitted);
- self.logs = ko.mapping.fromJS({'default': ''});
- self.coordVM = new RunningCoordinatorModel([]);
- self.properties = ko.observableDefault(job.properties, {});
- self.mainType = ko.observable(vm.interface());
- self.loadingJob = ko.observable(false);
- self.fetchJob = function () {
- self.loadingJob(true);
- hueUtils.changeURL('#!' + self.id()); // TODO build breacrumbs hash
- vm.breadcrumbs.push({'id': self.id(), 'name': self.name(), 'type': self.type()});
- $.post("/jobbrowser/api/job", {
- appid: ko.mapping.toJSON(self.id),
- interface: ko.mapping.toJSON(vm.interface)
- }, function (data) {
- if (data.status == 0) {
- vm.job(new Job(vm, data.app));
- vm.job().fetchLogs();
- if (self.mainType() == 'schedules') {
- vm.job().coordVM.setActions(data.app.actions);
- }
- } else {
- $(document).trigger("error", data.message);
- }
- }).always(function () {
- self.loadingJob(false);
- });
- };
- self.fetchLogs = function (name) {
- $.post("/jobbrowser/api/job/logs", {
- appid: ko.mapping.toJSON(self.id),
- interface: ko.mapping.toJSON(vm.interface),
- name: name ? name : 'default'
- }, function (data) {
- if (data.status == 0) {
- self.logs['default'](data.logs.logs['default'])
- } else {
- $(document).trigger("error", data.message);
- }
- }).always(function () {
- });
- };
- };
- var Jobs = function (vm, options) {
- var self = this;
- self.apps = ko.observableArray();
- self.loadingJobs = ko.observable(false);
- self.username = ko.observable('${ user.username }');
- self.fetchJobs = function () {
- self.loadingJobs(true);
- vm.job(null);
- $.post("/jobbrowser/api/jobs", {
- username: ko.mapping.toJSON(self.username),
- interface: ko.mapping.toJSON(vm.interface)
- }, function (data) {
- if (data.status == 0) {
- var apps = [];
- if (data && data.apps) {
- data.apps.forEach(function (job) { // TODO: update and merge
- apps.push(new Job(vm, job));
- });
- }
- self.apps(apps);
- } else {
- $(document).trigger("error", data.message);
- }
- }).always(function () {
- self.loadingJobs(false);
- });
- };
- };
- var JobBrowserViewModel = function (options, RunningCoordinatorModel) {
- var self = this;
- self.apiHelper = ApiHelper.getInstance(options);
- self.assistAvailable = ko.observable(true);
- self.isLeftPanelVisible = ko.observable();
- self.apiHelper.withTotalStorage('assist', 'assist_panel_visible', self.isLeftPanelVisible, true);
- self.jobs = new Jobs(self, options);
- self.job = ko.observable();
- //self.section = ko.observable('apps');
- self.interface = ko.observable('apps');
- self.interface.subscribe(function (val) {
- hueUtils.changeURL('#!' + val);
- self.breadcrumbs([{'id': '', 'name': val, 'type': val}]);
- self.jobs.fetchJobs();
- });
- self.breadcrumbs = ko.observableArray([]);
- self.breadcrumbs.push({'id': '', 'name': 'apps', 'type': 'apps'});
- self.paginationOffset = ko.observable(0);
- self.paginationResultPage = ko.observable(100);
- self.paginationPage = ko.observable(1);
- self.paginationResultCounts = ko.observable();
- };
- var viewModel;
- $(document).ready(function () {
- var options = {
- user: '${ user.username }',
- i18n: {
- errorLoadingDatabases: "${ _('There was a problem loading the databases') }",
- }
- };
- viewModel = new JobBrowserViewModel(options, RunningCoordinatorModel);
- ko.applyBindings(viewModel, $('#jobbrowserComponents')[0]);
- var loadHash = function () {
- var h = window.location.hash;
- if (h.indexOf('#!') === 0) {
- h = h.substr(2);
- }
- switch (h) {
- case 'schedules':
- case 'apps':
- case 'workflows':
- viewModel.interface(h);
- break;
- default:
- }
- }
- window.onhashchange = function () {
- loadHash();
- }
- loadHash();
- viewModel.jobs.fetchJobs();
- });
- })();
- </script>
- </span>
- % if not is_embeddable:
- ${ commonfooter(request, messages) | n,unicode }
- % endif
|