|
@@ -16,14 +16,14 @@
|
|
|
|
|
|
|
|
import ko from 'knockout';
|
|
import ko from 'knockout';
|
|
|
|
|
|
|
|
-import apiHelper from 'api/apiHelper';
|
|
|
|
|
-import AssistStorageEntry from 'ko/components/assist/assistStorageEntry';
|
|
|
|
|
|
|
+import apiHelper from '../../../api/apiHelper';
|
|
|
|
|
+import AssistStorageEntry from './assistStorageEntry';
|
|
|
import componentUtils from 'ko/components/componentUtils';
|
|
import componentUtils from 'ko/components/componentUtils';
|
|
|
-import huePubSub from 'utils/huePubSub';
|
|
|
|
|
|
|
+import huePubSub from '../../../utils/huePubSub';
|
|
|
import I18n from 'utils/i18n';
|
|
import I18n from 'utils/i18n';
|
|
|
|
|
|
|
|
-const HDFS_CONTEXT_ITEMS_TEMPLATE = `
|
|
|
|
|
- <script type="text/html" id="hdfs-context-items">
|
|
|
|
|
|
|
+const TEMPLATE = `
|
|
|
|
|
+ <script type="text/html" id="storage-context-items">
|
|
|
<li><a href="javascript:void(0);" data-bind="click: function (data) { showContextPopover(data, { target: $parentContext.$contextSourceElement }, { left: -15, top: 2 }); }"><i class="fa fa-fw fa-info"></i> ${I18n(
|
|
<li><a href="javascript:void(0);" data-bind="click: function (data) { showContextPopover(data, { target: $parentContext.$contextSourceElement }, { left: -15, top: 2 }); }"><i class="fa fa-fw fa-info"></i> ${I18n(
|
|
|
'Show details'
|
|
'Show details'
|
|
|
)}</a></li>
|
|
)}</a></li>
|
|
@@ -41,21 +41,18 @@ const HDFS_CONTEXT_ITEMS_TEMPLATE = `
|
|
|
)}</a></li>
|
|
)}</a></li>
|
|
|
<!-- /ko -->
|
|
<!-- /ko -->
|
|
|
</script>
|
|
</script>
|
|
|
-`;
|
|
|
|
|
|
|
|
|
|
-const TEMPLATE =
|
|
|
|
|
- HDFS_CONTEXT_ITEMS_TEMPLATE +
|
|
|
|
|
- `
|
|
|
|
|
- <script type="text/html" id="assist-hdfs-header-actions">
|
|
|
|
|
|
|
+ <script type="text/html" id="assist-storage-header-actions">
|
|
|
<div class="assist-db-header-actions">
|
|
<div class="assist-db-header-actions">
|
|
|
|
|
+ <!-- ko if: type !== 's3' -->
|
|
|
<a class="inactive-action" href="javascript:void(0)" data-bind="click: goHome, attr: { title: I18n('Go to ' + window.USER_HOME_DIR) }"><i class="pointer fa fa-home"></i></a>
|
|
<a class="inactive-action" href="javascript:void(0)" data-bind="click: goHome, attr: { title: I18n('Go to ' + window.USER_HOME_DIR) }"><i class="pointer fa fa-home"></i></a>
|
|
|
<!-- ko if: window.SHOW_UPLOAD_BUTTON -->
|
|
<!-- ko if: window.SHOW_UPLOAD_BUTTON -->
|
|
|
<a class="inactive-action" data-bind="dropzone: {
|
|
<a class="inactive-action" data-bind="dropzone: {
|
|
|
- url: '/filebrowser/upload/file?dest=' + path,
|
|
|
|
|
|
|
+ url: '/filebrowser/upload/file?dest=' + (type === 'adls' ? 'adl:' : '') + path,
|
|
|
params: { dest: path },
|
|
params: { dest: path },
|
|
|
paramName: 'hdfs_file',
|
|
paramName: 'hdfs_file',
|
|
|
onError: function(x, e){ $(document).trigger('error', e); },
|
|
onError: function(x, e){ $(document).trigger('error', e); },
|
|
|
- onComplete: function () { huePubSub.publish('assist.hdfs.refresh'); huePubSub.publish('fb.hdfs.refresh', path); } }" title="${I18n(
|
|
|
|
|
|
|
+ onComplete: function () { huePubSub.publish('assist.storage.refresh'); } }" title="${I18n(
|
|
|
'Upload file'
|
|
'Upload file'
|
|
|
)}" href="javascript:void(0)">
|
|
)}" href="javascript:void(0)">
|
|
|
<div class="dz-message inline" data-dz-message><i class="pointer fa fa-plus" title="${I18n(
|
|
<div class="dz-message inline" data-dz-message><i class="pointer fa fa-plus" title="${I18n(
|
|
@@ -63,40 +60,70 @@ const TEMPLATE =
|
|
|
)}"></i></div>
|
|
)}"></i></div>
|
|
|
</a>
|
|
</a>
|
|
|
<!-- /ko -->
|
|
<!-- /ko -->
|
|
|
- <a class="inactive-action" href="javascript:void(0)" data-bind="click: function () { huePubSub.publish('assist.hdfs.refresh'); }" title="${I18n(
|
|
|
|
|
|
|
+ <!-- /ko -->
|
|
|
|
|
+ <a class="inactive-action" href="javascript:void(0)" data-bind="click: function () { huePubSub.publish('assist.storage.refresh'); }" title="${I18n(
|
|
|
'Manual refresh'
|
|
'Manual refresh'
|
|
|
)}"><i class="pointer fa fa-refresh" data-bind="css: { 'fa-spin blue' : loading }"></i></a>
|
|
)}"><i class="pointer fa fa-refresh" data-bind="css: { 'fa-spin blue' : loading }"></i></a>
|
|
|
</div>
|
|
</div>
|
|
|
</script>
|
|
</script>
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
<!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
|
|
<!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
|
|
|
- <!-- ko with: selectedHdfsEntry -->
|
|
|
|
|
|
|
+
|
|
|
|
|
+ <!-- ko ifnot: activeSource -->
|
|
|
|
|
+ <div class="assist-flex-header">
|
|
|
|
|
+ <div class="assist-inner-header">
|
|
|
|
|
+ ${I18n('Sources')}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="assist-flex-fill">
|
|
|
|
|
+ <ul class="assist-tables" data-bind="foreach: sources">
|
|
|
|
|
+ <li class="assist-table">
|
|
|
|
|
+ <a class="assist-table-link" href="javascript: void(0);" data-bind="click: function () { $parent.activeSource($data); }"><i class="fa fa-fw fa-server muted valign-middle"></i> <span data-bind="text: $data.toUpperCase()"></span></a>
|
|
|
|
|
+ </li>
|
|
|
|
|
+ </ul>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <!-- /ko -->
|
|
|
|
|
+
|
|
|
|
|
+ <!-- ko if: activeSource -->
|
|
|
|
|
+ <!-- ko with: selectedStorageEntry -->
|
|
|
<div class="assist-flex-header assist-breadcrumb" >
|
|
<div class="assist-flex-header assist-breadcrumb" >
|
|
|
<!-- ko if: parent !== null -->
|
|
<!-- ko if: parent !== null -->
|
|
|
- <a href="javascript: void(0);" data-bind="appAwareTemplateContextMenu: { template: 'hdfs-context-items', scrollContainer: '.assist-hdfs-scrollable' }, click: function () { huePubSub.publish('assist.selectHdfsEntry', parent); }">
|
|
|
|
|
|
|
+ <a href="javascript: void(0);" data-bind="appAwareTemplateContextMenu: {
|
|
|
|
|
+ template: 'storage-context-items',
|
|
|
|
|
+ scrollContainer: '.assist-files-scrollable'
|
|
|
|
|
+ }, click: function () {
|
|
|
|
|
+ huePubSub.publish('assist.selectStorageEntry', parent);
|
|
|
|
|
+ }">
|
|
|
<i class="fa fa-fw fa-chevron-left"></i>
|
|
<i class="fa fa-fw fa-chevron-left"></i>
|
|
|
<i class="fa fa-fw fa-folder-o"></i>
|
|
<i class="fa fa-fw fa-folder-o"></i>
|
|
|
<span data-bind="text: definition.name, tooltip: {'title': path, 'placement': 'top' }"></span>
|
|
<span data-bind="text: definition.name, tooltip: {'title': path, 'placement': 'top' }"></span>
|
|
|
</a>
|
|
</a>
|
|
|
<!-- /ko -->
|
|
<!-- /ko -->
|
|
|
<!-- ko if: parent === null -->
|
|
<!-- ko if: parent === null -->
|
|
|
- <div>
|
|
|
|
|
- <i class="fa fa-fw fa-folder-o"></i>
|
|
|
|
|
- <span data-bind="text: path"></span>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <a href="javascript: void(0);" data-bind="click: function () { $parent.activeSource(undefined) }">
|
|
|
|
|
+ <i class="fa fa-fw fa-chevron-left"></i>
|
|
|
|
|
+ <i class="fa fa-fw fa-server"></i>
|
|
|
|
|
+ <span data-bind="text: $parent.activeSource().toUpperCase()"></span>
|
|
|
|
|
+ </a>
|
|
|
<!-- /ko -->
|
|
<!-- /ko -->
|
|
|
- <!-- ko template: 'assist-hdfs-header-actions' --><!-- /ko -->
|
|
|
|
|
|
|
+ <!-- ko template: 'assist-storage-header-actions' --><!-- /ko -->
|
|
|
</div>
|
|
</div>
|
|
|
<div class="assist-flex-search">
|
|
<div class="assist-flex-search">
|
|
|
- <div class="assist-filter"><input class="clearable" type="text" placeholder="${I18n(
|
|
|
|
|
- 'Filter...'
|
|
|
|
|
- )}" data-bind="clearable: filter, value: filter, valueUpdate: 'afterkeydown'"/></div>
|
|
|
|
|
|
|
+ <div class="assist-filter">
|
|
|
|
|
+ <form autocomplete="off">
|
|
|
|
|
+ <input class="clearable" type="text" placeholder="${I18n(
|
|
|
|
|
+ 'Filter...'
|
|
|
|
|
+ )}" autocorrect="off" autocomplete="do-not-autocomplete" autocapitalize="off" spellcheck="false"
|
|
|
|
|
+ data-bind="clearable: filter, value: filter, valueUpdate: 'afterkeydown'"/>
|
|
|
|
|
+ </form>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="assist-flex-fill assist-hdfs-scrollable" data-bind="delayedOverflow">
|
|
|
|
|
|
|
+
|
|
|
|
|
+ <div class="assist-flex-fill assist-storage-scrollable" data-bind="delayedOverflow">
|
|
|
<div data-bind="visible: ! loading() && ! hasErrors()" style="position: relative;">
|
|
<div data-bind="visible: ! loading() && ! hasErrors()" style="position: relative;">
|
|
|
<!-- ko hueSpinner: { spin: loadingMore, overlay: true } --><!-- /ko -->
|
|
<!-- ko hueSpinner: { spin: loadingMore, overlay: true } --><!-- /ko -->
|
|
|
- <ul class="assist-tables" data-bind="foreachVisible: { data: entries, minHeight: 22, container: '.assist-hdfs-scrollable', fetchMore: $data.fetchMore.bind($data) }">
|
|
|
|
|
- <li class="assist-entry assist-table-link" style="position: relative;" data-bind="appAwareTemplateContextMenu: { template: 'hdfs-context-items', scrollContainer: '.assist-hdfs-scrollable' }, visibleOnHover: { override: contextPopoverVisible, 'selector': '.assist-actions' }">
|
|
|
|
|
|
|
+ <ul class="assist-tables" data-bind="foreachVisible: { data: entries, minHeight: 22, container: '.assist-storage-scrollable', fetchMore: $data.fetchMore.bind($data) }">
|
|
|
|
|
+ <li class="assist-entry assist-table-link" style="position: relative;" data-bind="appAwareTemplateContextMenu: { template: 'storage-context-items', scrollContainer: '.assist-storage-scrollable' }, visibleOnHover: { override: contextPopoverVisible, 'selector': '.assist-actions' }">
|
|
|
<div class="assist-actions table-actions" style="opacity: 0;" >
|
|
<div class="assist-actions table-actions" style="opacity: 0;" >
|
|
|
<a style="padding: 0 3px;" class="inactive-action" href="javascript:void(0);" data-bind="click: showContextPopover, css: { 'blue': contextPopoverVisible }">
|
|
<a style="padding: 0 3px;" class="inactive-action" href="javascript:void(0);" data-bind="click: showContextPopover, css: { 'blue': contextPopoverVisible }">
|
|
|
<i class='fa fa-info' title="${I18n('Details')}"></i>
|
|
<i class='fa fa-info' title="${I18n('Details')}"></i>
|
|
@@ -110,7 +137,7 @@ const TEMPLATE =
|
|
|
<!-- ko if: definition.type === 'file' -->
|
|
<!-- ko if: definition.type === 'file' -->
|
|
|
<i class="fa fa-fw fa-file-o muted valign-middle"></i>
|
|
<i class="fa fa-fw fa-file-o muted valign-middle"></i>
|
|
|
<!-- /ko -->
|
|
<!-- /ko -->
|
|
|
- <span draggable="true" data-bind="text: definition.name, draggableText: { text: '\\'' + path + '\\'', meta: {'type': 'hdfs', 'definition': definition} }"></span>
|
|
|
|
|
|
|
+ <span draggable="true" data-bind="text: definition.name, draggableText: { text: '\\'' + path + '\\'', meta: {'type': type, 'definition': definition} }"></span>
|
|
|
</a>
|
|
</a>
|
|
|
</li>
|
|
</li>
|
|
|
</ul>
|
|
</ul>
|
|
@@ -128,72 +155,95 @@ const TEMPLATE =
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
<!-- /ko -->
|
|
<!-- /ko -->
|
|
|
|
|
+ <!-- /ko -->
|
|
|
`;
|
|
`;
|
|
|
|
|
|
|
|
-class AssistHdfsPanel {
|
|
|
|
|
|
|
+class AssistStoragePanel {
|
|
|
/**
|
|
/**
|
|
|
* @param {Object} options
|
|
* @param {Object} options
|
|
|
|
|
+ * @param {String[]} options.sources
|
|
|
* @constructor
|
|
* @constructor
|
|
|
**/
|
|
**/
|
|
|
constructor(options) {
|
|
constructor(options) {
|
|
|
- const self = this;
|
|
|
|
|
- self.selectedHdfsEntry = ko.observable();
|
|
|
|
|
- self.loading = ko.observable();
|
|
|
|
|
- self.initialized = false;
|
|
|
|
|
-
|
|
|
|
|
- const loadPath = path => {
|
|
|
|
|
- self.loading(true);
|
|
|
|
|
- const parts = path.split('/');
|
|
|
|
|
- parts.shift();
|
|
|
|
|
-
|
|
|
|
|
- const currentEntry = new AssistStorageEntry({
|
|
|
|
|
- type: 'hdfs',
|
|
|
|
|
- definition: {
|
|
|
|
|
- name: '/',
|
|
|
|
|
- type: 'dir'
|
|
|
|
|
- },
|
|
|
|
|
- parent: null
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- currentEntry.loadDeep(parts, entry => {
|
|
|
|
|
- self.selectedHdfsEntry(entry);
|
|
|
|
|
- entry.open(true);
|
|
|
|
|
- self.loading(false);
|
|
|
|
|
- });
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- self.reload = () => {
|
|
|
|
|
- loadPath(apiHelper.getFromTotalStorage('assist', 'currentHdfsPath', window.USER_HOME_DIR));
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- huePubSub.subscribe('assist.hdfs.go.home', () => {
|
|
|
|
|
- loadPath(window.USER_HOME_DIR);
|
|
|
|
|
- apiHelper.setInTotalStorage('assist', 'currentHdfsPath', window.USER_HOME_DIR);
|
|
|
|
|
|
|
+ this.sources = ko.observableArray(options.sources);
|
|
|
|
|
+
|
|
|
|
|
+ let lastSource = apiHelper.getFromTotalStorage('assist', 'lastStorageSource', 'hdfs');
|
|
|
|
|
+
|
|
|
|
|
+ if (options.sources.indexOf(lastSource) === -1) {
|
|
|
|
|
+ lastSource = options.sources.indexOf('hdfs') !== -1 ? 'hdfs' : options.sources[0];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.activeSource = ko.observable(lastSource);
|
|
|
|
|
+ this.loading = ko.observable();
|
|
|
|
|
+ this.initialized = false;
|
|
|
|
|
+
|
|
|
|
|
+ this.selectedStorageEntry = ko.observable();
|
|
|
|
|
+
|
|
|
|
|
+ this.activeSource.subscribe(newValue => {
|
|
|
|
|
+ if (newValue) {
|
|
|
|
|
+ apiHelper.setInTotalStorage('assist', 'lastStorageSource', newValue);
|
|
|
|
|
+ this.selectedStorageEntry(undefined);
|
|
|
|
|
+ this.reload();
|
|
|
|
|
+ }
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- huePubSub.subscribe('assist.selectHdfsEntry', entry => {
|
|
|
|
|
- self.selectedHdfsEntry(entry);
|
|
|
|
|
- apiHelper.setInTotalStorage('assist', 'currentHdfsPath', entry.path);
|
|
|
|
|
|
|
+ huePubSub.subscribe('assist.selectStorageEntry', entry => {
|
|
|
|
|
+ this.selectedStorageEntry(entry);
|
|
|
|
|
+ apiHelper.setInTotalStorage('assist', 'currentStoragePath_' + entry.type, entry.path);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- huePubSub.subscribe('assist.hdfs.refresh', () => {
|
|
|
|
|
- huePubSub.publish('assist.clear.hdfs.cache');
|
|
|
|
|
|
|
+ huePubSub.subscribe('assist.storage.refresh', () => {
|
|
|
|
|
+ apiHelper.clearStorageCache(this.activeSource());
|
|
|
self.reload();
|
|
self.reload();
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- self.init();
|
|
|
|
|
|
|
+ huePubSub.subscribe('assist.storage.go.home', () => {
|
|
|
|
|
+ const path = this.activeSource() === 's3' ? '/' : window.USER_HOME_DIR;
|
|
|
|
|
+ this.loadPath(path);
|
|
|
|
|
+ apiHelper.setInTotalStorage('assist', 'currentStoragePath_' + this.activeSource(), path);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ this.init();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ loadPath(path) {
|
|
|
|
|
+ this.loading(true);
|
|
|
|
|
+ const parts = path.split('/');
|
|
|
|
|
+ parts.shift();
|
|
|
|
|
+
|
|
|
|
|
+ const currentEntry = new AssistStorageEntry({
|
|
|
|
|
+ type: this.activeSource(),
|
|
|
|
|
+ definition: {
|
|
|
|
|
+ name: '/',
|
|
|
|
|
+ type: 'dir'
|
|
|
|
|
+ },
|
|
|
|
|
+ parent: null
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ currentEntry.loadDeep(parts, entry => {
|
|
|
|
|
+ this.selectedStorageEntry(entry);
|
|
|
|
|
+ entry.open(true);
|
|
|
|
|
+ this.loading(false);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ reload() {
|
|
|
|
|
+ this.loadPath(
|
|
|
|
|
+ apiHelper.getFromTotalStorage(
|
|
|
|
|
+ 'assist',
|
|
|
|
|
+ 'currentStoragePath_' + this.activeSource(),
|
|
|
|
|
+ this.activeSource() === 'hdfs' ? window.USER_HOME_DIR : '/'
|
|
|
|
|
+ )
|
|
|
|
|
+ );
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
init() {
|
|
init() {
|
|
|
- const self = this;
|
|
|
|
|
- if (self.initialized) {
|
|
|
|
|
|
|
+ if (this.initialized) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
- self.reload();
|
|
|
|
|
- self.initialized = true;
|
|
|
|
|
|
|
+ this.reload();
|
|
|
|
|
+ this.initialized = true;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-componentUtils.registerStaticComponent('hue-assist-hdfs-panel', AssistHdfsPanel, TEMPLATE);
|
|
|
|
|
-
|
|
|
|
|
-export default HDFS_CONTEXT_ITEMS_TEMPLATE;
|
|
|
|
|
|
|
+componentUtils.registerStaticComponent('hue-assist-storage-panel', AssistStoragePanel, TEMPLATE);
|