feat: SmartAssistant v2.5.0 — delete tools + expandable chat panel
Add delete_meeting, delete_call, delete_note tools for Shira. Add expand/collapse toggle button to the floating chat window. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,9 @@ define('modules/smart-assistant/views/floating-chat', ['view'], function (View)
|
|||||||
' <button class="btn btn-link sa-new-btn" type="button" title="{{translate \'New Conversation\' scope=\'SmartAssistant\'}}">' +
|
' <button class="btn btn-link sa-new-btn" type="button" title="{{translate \'New Conversation\' scope=\'SmartAssistant\'}}">' +
|
||||||
' <span class="fas fa-plus"></span>' +
|
' <span class="fas fa-plus"></span>' +
|
||||||
' </button>' +
|
' </button>' +
|
||||||
|
' <button class="btn btn-link sa-expand-btn" type="button" title="{{translate \'Expand\' scope=\'SmartAssistant\'}}">' +
|
||||||
|
' <span class="fas fa-expand-alt"></span>' +
|
||||||
|
' </button>' +
|
||||||
' <button class="btn btn-link sa-close-btn" type="button">' +
|
' <button class="btn btn-link sa-close-btn" type="button">' +
|
||||||
' <span class="fas fa-times"></span>' +
|
' <span class="fas fa-times"></span>' +
|
||||||
' </button>' +
|
' </button>' +
|
||||||
@@ -67,7 +70,10 @@ define('modules/smart-assistant/views/floating-chat', ['view'], function (View)
|
|||||||
'.sa-fab:hover { transform: scale(1.08); }' +
|
'.sa-fab:hover { transform: scale(1.08); }' +
|
||||||
'.sa-fab-avatar { width: 100%; height: 100%; object-fit: cover; }' +
|
'.sa-fab-avatar { width: 100%; height: 100%; object-fit: cover; }' +
|
||||||
'.sa-fab-badge { position: absolute; top: -4px; right: -4px; background: #c62828; color: #fff; border-radius: 10px; min-width: 20px; height: 20px; font-size: 11px; font-weight: bold; display: flex; align-items: center; justify-content: center; padding: 0 5px; z-index: 1; }' +
|
'.sa-fab-badge { position: absolute; top: -4px; right: -4px; background: #c62828; color: #fff; border-radius: 10px; min-width: 20px; height: 20px; font-size: 11px; font-weight: bold; display: flex; align-items: center; justify-content: center; padding: 0 5px; z-index: 1; }' +
|
||||||
'.sa-chat-panel { position: absolute; bottom: 68px; left: 0; width: 400px; max-height: 600px; background: #fff; border-radius: 12px; box-shadow: 0 8px 32px rgba(0,0,0,0.18); display: flex; flex-direction: column; overflow: hidden; animation: sa-slide-up 0.25s ease-out; }' +
|
'.sa-chat-panel { position: absolute; bottom: 68px; left: 0; width: 400px; max-height: 600px; background: #fff; border-radius: 12px; box-shadow: 0 8px 32px rgba(0,0,0,0.18); display: flex; flex-direction: column; overflow: hidden; animation: sa-slide-up 0.25s ease-out; transition: width 0.3s ease, max-height 0.3s ease; }' +
|
||||||
|
'.sa-chat-panel.sa-expanded { width: 700px; max-height: 85vh; }' +
|
||||||
|
'.sa-chat-panel.sa-expanded .sa-chat-messages { max-height: calc(85vh - 180px); }' +
|
||||||
|
'.sa-chat-panel.sa-expanded .sa-history-list, .sa-chat-panel.sa-expanded .sa-memory-list { max-height: calc(85vh - 200px); }' +
|
||||||
'@keyframes sa-slide-up { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } }' +
|
'@keyframes sa-slide-up { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } }' +
|
||||||
'.sa-chat-header { display: flex; align-items: center; padding: 10px 16px; background: #5c6bc0; color: #fff; gap: 8px; }' +
|
'.sa-chat-header { display: flex; align-items: center; padding: 10px 16px; background: #5c6bc0; color: #fff; gap: 8px; }' +
|
||||||
'.sa-chat-title { font-size: 15px; font-weight: 600; white-space: nowrap; }' +
|
'.sa-chat-title { font-size: 15px; font-weight: 600; white-space: nowrap; }' +
|
||||||
@@ -122,7 +128,7 @@ define('modules/smart-assistant/views/floating-chat', ['view'], function (View)
|
|||||||
'.sa-badge-source { background: #f3e5f5; color: #7b1fa2; }' +
|
'.sa-badge-source { background: #f3e5f5; color: #7b1fa2; }' +
|
||||||
'.sa-memory-entry-content { font-size: 12px; color: #555; line-height: 1.4; max-height: 60px; overflow: hidden; }' +
|
'.sa-memory-entry-content { font-size: 12px; color: #555; line-height: 1.4; max-height: 60px; overflow: hidden; }' +
|
||||||
'.sa-memory-entry-meta { font-size: 10px; color: #999; margin-top: 4px; }' +
|
'.sa-memory-entry-meta { font-size: 10px; color: #999; margin-top: 4px; }' +
|
||||||
'@media (max-width: 480px) { .sa-chat-panel { width: calc(100vw - 48px); left: 0; } .smart-assistant-fab-container { bottom: 16px; left: 16px; } }' +
|
'@media (max-width: 480px) { .sa-chat-panel { width: calc(100vw - 48px); left: 0; } .sa-chat-panel.sa-expanded { width: calc(100vw - 48px); } .smart-assistant-fab-container { bottom: 16px; left: 16px; } }' +
|
||||||
'</style>',
|
'</style>',
|
||||||
|
|
||||||
conversationId: null,
|
conversationId: null,
|
||||||
@@ -131,12 +137,14 @@ define('modules/smart-assistant/views/floating-chat', ['view'], function (View)
|
|||||||
currentCaseId: null,
|
currentCaseId: null,
|
||||||
currentCaseName: null,
|
currentCaseName: null,
|
||||||
currentView: 'chat',
|
currentView: 'chat',
|
||||||
|
isExpanded: false,
|
||||||
currentMemoryCategory: null,
|
currentMemoryCategory: null,
|
||||||
memoryData: null,
|
memoryData: null,
|
||||||
|
|
||||||
events: {
|
events: {
|
||||||
'click .sa-fab': function () { this.togglePanel(); },
|
'click .sa-fab': function () { this.togglePanel(); },
|
||||||
'click .sa-close-btn': function () { this.closePanel(); },
|
'click .sa-close-btn': function () { this.closePanel(); },
|
||||||
|
'click .sa-expand-btn': function () { this.toggleExpand(); },
|
||||||
'click .sa-chat-send': function () { this.sendMessage(); },
|
'click .sa-chat-send': function () { this.sendMessage(); },
|
||||||
'click .sa-history-btn': function () { this.showHistory(); },
|
'click .sa-history-btn': function () { this.showHistory(); },
|
||||||
'click .sa-new-btn': function () { this.startNewConversation(); },
|
'click .sa-new-btn': function () { this.startNewConversation(); },
|
||||||
@@ -260,7 +268,26 @@ define('modules/smart-assistant/views/floating-chat', ['view'], function (View)
|
|||||||
|
|
||||||
closePanel: function () {
|
closePanel: function () {
|
||||||
this.isOpen = false;
|
this.isOpen = false;
|
||||||
this.$el.find('.sa-chat-panel').css('display', 'none');
|
this.isExpanded = false;
|
||||||
|
var $panel = this.$el.find('.sa-chat-panel');
|
||||||
|
$panel.removeClass('sa-expanded').css('display', 'none');
|
||||||
|
this.$el.find('.sa-expand-btn .fas').removeClass('fa-compress-alt').addClass('fa-expand-alt');
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleExpand: function () {
|
||||||
|
this.isExpanded = !this.isExpanded;
|
||||||
|
var $panel = this.$el.find('.sa-chat-panel');
|
||||||
|
var $icon = this.$el.find('.sa-expand-btn .fas');
|
||||||
|
|
||||||
|
if (this.isExpanded) {
|
||||||
|
$panel.addClass('sa-expanded');
|
||||||
|
$icon.removeClass('fa-expand-alt').addClass('fa-compress-alt');
|
||||||
|
} else {
|
||||||
|
$panel.removeClass('sa-expanded');
|
||||||
|
$icon.removeClass('fa-compress-alt').addClass('fa-expand-alt');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scrollToBottom();
|
||||||
},
|
},
|
||||||
|
|
||||||
showChat: function () {
|
showChat: function () {
|
||||||
@@ -741,7 +768,7 @@ define('modules/smart-assistant/views/floating-chat', ['view'], function (View)
|
|||||||
recordView.model.trigger('update-all');
|
recordView.model.trigger('update-all');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entityType === 'Task' || entityType === 'Meeting') {
|
if (entityType === 'Task' || entityType === 'Meeting' || entityType === 'Call') {
|
||||||
var sideView = currentView.getView('side');
|
var sideView = currentView.getView('side');
|
||||||
|
|
||||||
if (sideView) {
|
if (sideView) {
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ class ActionExecutor
|
|||||||
'change_status' => $this->changeStatus($params, $caseId),
|
'change_status' => $this->changeStatus($params, $caseId),
|
||||||
'create_meeting' => $this->createMeeting($params, $caseId, $userId),
|
'create_meeting' => $this->createMeeting($params, $caseId, $userId),
|
||||||
'create_call' => $this->createCall($params, $caseId, $userId),
|
'create_call' => $this->createCall($params, $caseId, $userId),
|
||||||
|
'delete_meeting' => $this->deleteMeeting($params),
|
||||||
|
'delete_call' => $this->deleteCall($params),
|
||||||
|
'delete_note' => $this->deleteNote($params),
|
||||||
'schedule_hearing' => $this->scheduleHearing($params, $caseId, $userId),
|
'schedule_hearing' => $this->scheduleHearing($params, $caseId, $userId),
|
||||||
'list_documents' => $this->listDocuments($caseId),
|
'list_documents' => $this->listDocuments($caseId),
|
||||||
'analyze_document' => $this->analyzeDocument($params, $caseId),
|
'analyze_document' => $this->analyzeDocument($params, $caseId),
|
||||||
@@ -217,6 +220,74 @@ class ActionExecutor
|
|||||||
return ['success' => true, 'message' => "✅ שיחה \"{$params['name']}\" תועדה בהצלחה", 'entityType' => 'Call', 'entityId' => $call->get('id')];
|
return ['success' => true, 'message' => "✅ שיחה \"{$params['name']}\" תועדה בהצלחה", 'entityType' => 'Call', 'entityId' => $call->get('id')];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function deleteMeeting(array $params): array
|
||||||
|
{
|
||||||
|
$entityId = $params['entityId'] ?? null;
|
||||||
|
if (!$entityId) {
|
||||||
|
throw new Error('entityId parameter is required.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$entity = $this->entityManager->getEntityById('Meeting', $entityId);
|
||||||
|
if (!$entity) {
|
||||||
|
throw new NotFound("Meeting {$entityId} not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = $entity->get('name') ?? '';
|
||||||
|
$this->entityManager->removeEntity($entity);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'message' => "✅ פגישה \"{$name}\" נמחקה בהצלחה",
|
||||||
|
'entityType' => 'Meeting',
|
||||||
|
'entityId' => $entityId,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function deleteCall(array $params): array
|
||||||
|
{
|
||||||
|
$entityId = $params['entityId'] ?? null;
|
||||||
|
if (!$entityId) {
|
||||||
|
throw new Error('entityId parameter is required.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$entity = $this->entityManager->getEntityById('Call', $entityId);
|
||||||
|
if (!$entity) {
|
||||||
|
throw new NotFound("Call {$entityId} not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = $entity->get('name') ?? '';
|
||||||
|
$this->entityManager->removeEntity($entity);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'message' => "✅ שיחה \"{$name}\" נמחקה בהצלחה",
|
||||||
|
'entityType' => 'Call',
|
||||||
|
'entityId' => $entityId,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function deleteNote(array $params): array
|
||||||
|
{
|
||||||
|
$entityId = $params['entityId'] ?? null;
|
||||||
|
if (!$entityId) {
|
||||||
|
throw new Error('entityId parameter is required.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$entity = $this->entityManager->getEntityById('Note', $entityId);
|
||||||
|
if (!$entity) {
|
||||||
|
throw new NotFound("Note {$entityId} not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->entityManager->removeEntity($entity);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'message' => '✅ הערה נמחקה בהצלחה',
|
||||||
|
'entityType' => 'Note',
|
||||||
|
'entityId' => $entityId,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
private function scheduleHearing(array $params, ?string $caseId, string $userId): array
|
private function scheduleHearing(array $params, ?string $caseId, string $userId): array
|
||||||
{
|
{
|
||||||
$case = $this->entityManager->getEntityById('Case', $caseId);
|
$case = $this->entityManager->getEntityById('Case', $caseId);
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
"module": "SmartAssistant",
|
"module": "SmartAssistant",
|
||||||
"description": "Unified AI Assistant for Legal CRM — floating chat with case memory, office alerts, and AI Gateway integration",
|
"description": "Unified AI Assistant for Legal CRM — floating chat with case memory, office alerts, and AI Gateway integration",
|
||||||
"author": "klear",
|
"author": "klear",
|
||||||
"version": "2.4.0",
|
"version": "2.5.0",
|
||||||
"acceptableVersions": [
|
"acceptableVersions": [
|
||||||
">=8.0.0"
|
">=8.0.0"
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user