|
|
@@ -2710,6 +2710,189 @@ from desktop.views import _ko
|
|
|
})();
|
|
|
</script>
|
|
|
|
|
|
+ <script type="text/html" id="chat-panel-template">
|
|
|
+ <div class="assist-inner-panel">
|
|
|
+ <div class="assist-flex-panel">
|
|
|
+ <style>
|
|
|
+ .display-area {
|
|
|
+ overflow-y: auto;
|
|
|
+ background-color: #fff;
|
|
|
+ padding: 10px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ }
|
|
|
+ .message {
|
|
|
+ padding: 10px 14px;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ max-width: 95%;
|
|
|
+ word-wrap: break-word;
|
|
|
+ line-height: 1.5;
|
|
|
+ border-radius: 18px;
|
|
|
+ padding-bottom: 3px;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* AI 消息:靠左,蓝色背景 */
|
|
|
+ .ai-message {
|
|
|
+ align-self: flex-start;
|
|
|
+ background-color: #e3f2fd;
|
|
|
+ color: #0a0a0a;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 用户消息:靠右,绿色背景 */
|
|
|
+ .user-message {
|
|
|
+ align-self: flex-end;
|
|
|
+ background-color: #c8e6c9;
|
|
|
+ color: #0a0a0a;
|
|
|
+ }
|
|
|
+
|
|
|
+ .input-area {
|
|
|
+ display: flex;
|
|
|
+ padding: 10px;
|
|
|
+ background-color: #f9f9f9;
|
|
|
+ border-top: 1px solid #eee;
|
|
|
+ }
|
|
|
+
|
|
|
+ .user-input {
|
|
|
+ flex: 1;
|
|
|
+ padding: 10px 10px 10px 15px;
|
|
|
+ border: 1px solid #ccc;
|
|
|
+ border-radius: 4px;
|
|
|
+ outline: none;
|
|
|
+ resize: none;
|
|
|
+ overflow-y: auto;
|
|
|
+ scrollbar-gutter: stable;
|
|
|
+ min-height: auto;
|
|
|
+ max-height: 100px;
|
|
|
+ line-height: 1.5;
|
|
|
+ font-size: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .send-btn {
|
|
|
+ margin-left: 10px;
|
|
|
+ padding: 1px 15px;
|
|
|
+ background-color: #007bff;
|
|
|
+ color: white;
|
|
|
+ border: none;
|
|
|
+ border-radius: 4px;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ .send-btn:hover {
|
|
|
+ background-color: #0056b3;
|
|
|
+ }
|
|
|
+
|
|
|
+ </style>
|
|
|
+ <div class="assist-flex-header">
|
|
|
+ <div class="assist-inner-header">
|
|
|
+ <div class="function-dialect-dropdown" data-bind="component: { name: 'hue-drop-down', params: { fixedPosition: true, value: activeType, entries: availableTypes, linkTitle: '${ _ko('Selected dialect') }' } }" style="display: inline-block"></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 显示区域 -->
|
|
|
+ <div class="display-area" data-bind="foreach: messages">
|
|
|
+ <!-- 消息 -->
|
|
|
+ <div class="message" data-bind="html: content, css:{ 'ai-message': type==='ai', user-message: type==='user'}"></div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 输入区域 -->
|
|
|
+ <div class="input-area">
|
|
|
+ <textarea class="user-input clearable" placeholder="请输入你的问题..."
|
|
|
+ data-bind="clearable: query, textInput: query, event: { keydown: ask, input: autoResize} "></textarea>
|
|
|
+ <button class="send-btn" data-bind="click: answer">发送</button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </script>
|
|
|
+
|
|
|
+ <script type="text/javascript">
|
|
|
+ (function () {
|
|
|
+
|
|
|
+ function ChatPanel(params) {
|
|
|
+ let self = this;
|
|
|
+ self.disposals = [];
|
|
|
+
|
|
|
+ self.activeType = ko.observable();
|
|
|
+ self.availableTypes = ko.observableArray(window.IS_EMBEDDED ? ['Impala'] : ['Hive', 'Impala', 'Pig']);
|
|
|
+ self.query = ko.observable().extend({ rateLimit: 400 });
|
|
|
+ self.messages = ko.observableArray([]);
|
|
|
+
|
|
|
+ self.availableTypes().forEach(function (type) {
|
|
|
+ self.initFunctions(type);
|
|
|
+ });
|
|
|
+
|
|
|
+ let apiHelper = ApiHelper.getInstance();
|
|
|
+
|
|
|
+ self.activeType.subscribe(function (newType) {
|
|
|
+ apiHelper.setInTotalStorage('assist', 'chat.panel.active.type', newType);
|
|
|
+ });
|
|
|
+
|
|
|
+ let lastActiveType = apiHelper.getFromTotalStorage('assist', 'chat.panel.active.type', self.availableTypes()[0]);
|
|
|
+ self.activeType(lastActiveType);
|
|
|
+
|
|
|
+ let updateType = function (type) {
|
|
|
+ self.availableTypes().every(function (availableType) {
|
|
|
+ if (availableType.toLowerCase() === type) {
|
|
|
+ if (self.activeType() !== availableType) {
|
|
|
+ self.activeType(availableType);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ var activeSnippetTypeSub = huePubSub.subscribe('active.snippet.type.changed', updateType);
|
|
|
+
|
|
|
+ self.disposals.push(function () {
|
|
|
+ activeSnippetTypeSub.remove();
|
|
|
+ });
|
|
|
+
|
|
|
+ huePubSub.subscribeOnce('set.active.snippet.type', updateType);
|
|
|
+ huePubSub.publish('get.active.snippet.type');
|
|
|
+
|
|
|
+ var autoResize = function (data, event) {
|
|
|
+ var inputArea = event.target;
|
|
|
+ inputArea.style.height = 'auto';
|
|
|
+ inputArea.style.height = inputArea.scrollHeight + 'px';
|
|
|
+ };
|
|
|
+
|
|
|
+ autoResize();
|
|
|
+ }
|
|
|
+
|
|
|
+ ChatPanel.prototype.dispose = function () {
|
|
|
+ let self = this;
|
|
|
+ self.disposals.forEach(function (dispose) {
|
|
|
+ dispose();
|
|
|
+ })
|
|
|
+ };
|
|
|
+
|
|
|
+ ChatPanel.prototype.ask = function (data, event) {
|
|
|
+ let self = this;
|
|
|
+ if (event.key === 'Enter' || event.keyCode === 13) {
|
|
|
+ self.answer();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ ChatPanel.prototype.answer = function () {
|
|
|
+ let self = this;
|
|
|
+ if (self.query.trim() === '') {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ self.messages.push({type:'user', content: self.query().trim()});
|
|
|
+ self.messages.push({type:'ai', content: '感谢提问!我已经收到你的消息:' + self.query().trim()});
|
|
|
+ };
|
|
|
+
|
|
|
+ ChatPanel.prototype.initFunctions = function (dialect) {
|
|
|
+ var self = this;
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ ko.components.register('chat-panel', {
|
|
|
+ viewModel: ChatPanel,
|
|
|
+ template: { element: 'chat-panel-template' }
|
|
|
+ });
|
|
|
+ })();
|
|
|
+ </script>
|
|
|
+
|
|
|
<script type="text/html" id="editor-assistant-panel-template">
|
|
|
<div class="assist-inner-panel assist-assistant-panel">
|
|
|
<div class="assist-flex-panel">
|
|
|
@@ -3615,7 +3798,7 @@ from desktop.views import _ko
|
|
|
<div class="right-assist-tab" data-bind="visible: editorAssistantTabAvailable" style="display:none;"><a class="inactive-action" href="javascript: void(0);" title="${ _('Assistant') }" data-bind="css: { 'blue' : activeTab() === 'editorAssistant' }, tooltip: { placement: 'left' }, click: editorAssistantTabClick"><i class="fa fa-fw fa-compass"></i></a></div>
|
|
|
<div class="right-assist-tab" data-bind="visible: dashboardAssistantTabAvailable" style="display:none;"><a class="inactive-action" href="javascript: void(0);" title="${ _('Assistant') }" data-bind="css: { 'blue' : activeTab() === 'dashboardAssistant' }, tooltip: { placement: 'left' }, click: dashboardAssistantTabClick"><i class="fa fa-fw fa-compass"></i></a></div>
|
|
|
<div class="right-assist-tab" data-bind="visible: functionsTabAvailable" style="display:none;"><a class="inactive-action" href="javascript: void(0);" title="${ _('Functions') }" data-bind="css: { 'blue' : activeTab() === 'functions' }, tooltip: { placement: 'left' }, click: functionsTabClick"><i class="fa fa-fw fa-superscript"></i></a></div>
|
|
|
- <div class="right-assist-tab" data-bind="visible: functionsTabAvailable" style="display:none;"><a class="inactive-action" href="javascript: void(0);" title="${ _('Functions') }" data-bind="css: { 'blue' : activeTab() === 'functions' }, tooltip: { placement: 'left' }, click: functionsTabClick"><i class="fa fa-fw fa-comments"></i></a></div>
|
|
|
+ <div class="right-assist-tab" data-bind="visible: chatTabAvailable" style="display:none;"><a class="inactive-action" href="javascript: void(0);" title="${ _('Functions') }" data-bind="css: { 'blue' : activeTab() === 'chat' }, tooltip: { placement: 'left' }, click: chatTabClick"><i class="fa fa-fw fa-comments"></i></a></div>
|
|
|
<div class="right-assist-tab" data-bind="visible: langRefTabAvailable" style="display:none;"><a class="inactive-action" href="javascript: void(0);" title="${ _('Language Reference') }" data-bind="css: { 'blue' : activeTab() === 'langRef' }, tooltip: { placement: 'left' }, click: langRefTabClick"><i class="fa fa-fw fa-book"></i></a></div>
|
|
|
<div class="right-assist-tab" data-bind="visible: schedulesTabAvailable" style="display:none;"><a class="inactive-action" href="javascript: void(0);" title="${ _('Schedule') }" data-bind="css: { 'blue' : activeTab() === 'schedules' }, tooltip: { placement: 'left' }, click: schedulesTabClick"><i class="fa fa-fw fa-calendar"></i></a></div>
|
|
|
</div>
|
|
|
@@ -3630,6 +3813,10 @@ from desktop.views import _ko
|
|
|
<div data-bind="component: { name: 'functions-panel' }, visible: activeTab() === 'functions'"></div>
|
|
|
<!-- /ko -->
|
|
|
|
|
|
+ <!-- ko if: chatTabAvailable -->
|
|
|
+ <div data-bind="component: { name: 'chat-panel', params: { activeTab: activeTab } }, visible: activeTab() === 'chat'"></div>
|
|
|
+ <!-- /ko -->
|
|
|
+
|
|
|
<!-- ko if: langRefTabAvailable -->Functions
|
|
|
<div data-bind="component: { name: 'language-reference-panel' }, visible: activeTab() === 'langRef'"></div>
|
|
|
<!-- /ko -->
|
|
|
@@ -3651,6 +3838,7 @@ from desktop.views import _ko
|
|
|
var EDITOR_ASSISTANT_TAB = 'editorAssistant';
|
|
|
var DASHBOARD_ASSISTANT_TAB = 'dashboardAssistant';
|
|
|
var FUNCTIONS_TAB = 'functions';
|
|
|
+ var CHAT_TAB = 'chat';
|
|
|
var SCHEDULES_TAB = 'schedules';
|
|
|
var LANG_REF_TAB = 'langRef';
|
|
|
|
|
|
@@ -3664,6 +3852,7 @@ from desktop.views import _ko
|
|
|
self.editorAssistantTabAvailable = ko.observable(false);
|
|
|
self.dashboardAssistantTabAvailable = ko.observable(false);
|
|
|
self.functionsTabAvailable = ko.observable(false);
|
|
|
+ self.chatTabAvailable = ko.observable(false);
|
|
|
self.langRefTabAvailable = ko.observable(false);
|
|
|
self.schedulesTabAvailable = ko.observable(false);
|
|
|
|
|
|
@@ -3700,6 +3889,8 @@ from desktop.views import _ko
|
|
|
self.activeTab(EDITOR_ASSISTANT_TAB);
|
|
|
} else if (self.functionsTabAvailable()) {
|
|
|
self.activeTab(FUNCTIONS_TAB);
|
|
|
+ } else if (self.chatTabAvailable()) {
|
|
|
+ self.activeTab(CHAT_TAB);
|
|
|
} else if (self.schedulesTabAvailable()) {
|
|
|
self.activeTab(SCHEDULES_TAB);
|
|
|
} else if (self.dashboardAssistantTabAvailable()) {
|
|
|
@@ -3711,6 +3902,7 @@ from desktop.views import _ko
|
|
|
|
|
|
var updateContentsForType = function (type) {
|
|
|
self.functionsTabAvailable(type === 'hive' || type === 'impala' || type === 'pig');
|
|
|
+ self.chatTabAvailable(type === 'hive' || type === 'impala' || type === 'pig');
|
|
|
self.langRefTabAvailable(type === 'impala');
|
|
|
self.editorAssistantTabAvailable((!window.IS_EMBEDDED || window.EMBEDDED_ASSISTANT_ENABLED) && (type === 'hive' || type === 'impala'));
|
|
|
self.dashboardAssistantTabAvailable(type === 'dashboard');
|
|
|
@@ -3776,6 +3968,12 @@ from desktop.views import _ko
|
|
|
self.switchTab(FUNCTIONS_TAB);
|
|
|
};
|
|
|
|
|
|
+ RightAssistPanel.prototype.chatTabClick = function () {
|
|
|
+ var self = this;
|
|
|
+ self.lastActiveTabEditor(CHAT_TAB);
|
|
|
+ self.switchTab(CHAT_TAB);
|
|
|
+ };
|
|
|
+
|
|
|
RightAssistPanel.prototype.langRefTabClick = function () {
|
|
|
var self = this;
|
|
|
self.lastActiveTabEditor(LANG_REF_TAB);
|