Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ azd up
- The container already starts Gunicorn through `application/single_app/Dockerfile`.
- If your environment needs private or self-signed certificate authorities for outbound TLS checks to internal services, add them during image build using [docs/how-to/docker_customization.md](docs/how-to/docker_customization.md).

## Native Python
### Native Python
- For **native Python App Service** deployments, deploy the `application/single_app` folder and set the App Service Startup command explicitly.

Native Python deployment references:
Expand Down
1 change: 1 addition & 0 deletions application/single_app/functions_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ def get_settings(use_cosmos=False, include_source=False):
'enable_support_send_feedback': True,
'support_feedback_recipient_email': '',
'enable_support_latest_features': True,
'enable_support_latest_feature_documentation_links': False,
'support_latest_features_visibility': get_default_support_latest_features_visibility(),

# Enhanced Citations
Expand Down
10 changes: 10 additions & 0 deletions application/single_app/route_frontend_admin_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
from admin_settings_int_utils import safe_int_with_source
from support_menu_config import (
get_support_latest_feature_catalog,
get_support_latest_feature_release_groups,
get_support_latest_feature_release_groups_for_settings,
has_visible_support_latest_features,
normalize_support_latest_features_visibility,
)
Expand Down Expand Up @@ -123,6 +125,8 @@ def admin_settings():
settings['support_feedback_recipient_email'] = ''
if 'enable_support_latest_features' not in settings:
settings['enable_support_latest_features'] = True
if 'enable_support_latest_feature_documentation_links' not in settings:
settings['enable_support_latest_feature_documentation_links'] = False
settings['support_latest_features_visibility'] = normalize_support_latest_features_visibility(
settings.get('support_latest_features_visibility', {})
)
Expand Down Expand Up @@ -368,6 +372,8 @@ def admin_settings():
latest_version=latest_version,
download_url=download_url,
support_latest_feature_catalog=get_support_latest_feature_catalog(),
support_latest_feature_release_groups=get_support_latest_feature_release_groups(),
support_latest_feature_release_groups_preview=get_support_latest_feature_release_groups_for_settings(settings),
chunk_size_defaults=get_chunk_size_defaults(),
chunk_size_settings=settings.get('chunk_size', {}),
chunk_size_cap=get_chunk_size_cap(settings),
Expand Down Expand Up @@ -566,6 +572,9 @@ def parse_admin_int(raw_value, fallback_value, field_name="unknown", hard_defaul
enable_support_send_feedback = False

enable_support_latest_features = form_data.get('enable_support_latest_features') == 'on'
enable_support_latest_feature_documentation_links = (
form_data.get('enable_support_latest_feature_documentation_links') == 'on'
)
support_latest_features_visibility = {}
for feature in get_support_latest_feature_catalog():
field_name = f"support_latest_feature_{feature['id']}"
Expand Down Expand Up @@ -1210,6 +1219,7 @@ def is_valid_url(url):
'enable_support_send_feedback': enable_support_send_feedback,
'support_feedback_recipient_email': support_feedback_recipient_email,
'enable_support_latest_features': enable_support_latest_features,
'enable_support_latest_feature_documentation_links': enable_support_latest_feature_documentation_links,
'support_latest_features_visibility': support_latest_features_visibility,

# Enhanced Citations
Expand Down
19 changes: 17 additions & 2 deletions application/single_app/route_frontend_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
from functions_authentication import *
from functions_settings import *
from swagger_wrapper import swagger_route, get_auth_security
from support_menu_config import get_visible_support_latest_features
from support_menu_config import (
get_visible_support_latest_feature_groups,
get_visible_support_latest_features,
)


def _support_menu_access_allowed():
Expand All @@ -30,9 +33,21 @@ def support_latest_features():
return 'Not Found', 404

visible_features = get_visible_support_latest_features(settings)
visible_feature_groups = get_visible_support_latest_feature_groups(settings)
current_release_features = []
previous_release_feature_groups = []

for feature_group in visible_feature_groups:
if feature_group.get('id') == 'current_release':
current_release_features = feature_group.get('features', [])
else:
previous_release_feature_groups.append(feature_group)

return render_template(
'latest_features.html',
support_latest_features=visible_features,
support_latest_features=current_release_features or visible_features,
support_latest_feature_groups=visible_feature_groups,
support_previous_release_feature_groups=previous_release_feature_groups,
)

@app.route('/support/send-feedback')
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
90 changes: 69 additions & 21 deletions application/single_app/static/js/chat/chat-documents.js
Original file line number Diff line number Diff line change
Expand Up @@ -1323,6 +1323,74 @@ function syncTagsDropdownButtonText() {
}
}


export async function ensureSearchDocumentsVisible() {
if (!searchDocumentsBtn || !searchDocumentsContainer) {
return false;
}

searchDocumentsBtn.classList.add('active');
searchDocumentsContainer.style.display = 'block';

if (scopeLocked === true) {
rebuildScopeDropdownWithLock();
} else {
buildScopeDropdown();
}

await loadAllDocs();
await loadTagsForScope();

try {
const dropdownInstance = bootstrap.Dropdown.getInstance(docDropdownButton);
if (dropdownInstance) {
dropdownInstance.update();
}
} catch (err) {
console.error('Error updating document dropdown:', err);
}

handleDocumentSelectChange();
return true;
}


function openDropdown(buttonElement) {
if (!buttonElement) {
return false;
}

try {
bootstrap.Dropdown.getOrCreateInstance(buttonElement, {
autoClose: 'outside'
}).show();
buttonElement.focus();
return true;
} catch (err) {
console.error('Error opening dropdown:', err);
return false;
}
}


export function openScopeDropdown() {
return openDropdown(scopeDropdownButton);
}


export function openTagsDropdown() {
if (!tagsDropdown || !tagsDropdownButton) {
return false;
}

if (tagsDropdown.style.display === 'none' && (!tagsDropdownItems || !tagsDropdownItems.children.length)) {
return false;
}

showTagsDropdown();
return openDropdown(tagsDropdownButton);
}

/* ---------------------------------------------------------------------------
Get Selected Tags
--------------------------------------------------------------------------- */
Expand Down Expand Up @@ -1541,27 +1609,7 @@ if (searchDocumentsBtn) {
if (!searchDocumentsContainer) return;

if (this.classList.contains("active")) {
searchDocumentsContainer.style.display = "block";
// Build the scope dropdown on first open (respect lock state)
if (scopeLocked === true) {
rebuildScopeDropdownWithLock();
} else {
buildScopeDropdown();
}
// Ensure initial population and state is correct when opening
loadAllDocs().then(() => {
// Load tags for the currently selected scope
loadTagsForScope();
// Update Bootstrap Popper positioning if dropdown was already initialized
try {
const dropdownInstance = bootstrap.Dropdown.getInstance(docDropdownButton);
if (dropdownInstance) {
dropdownInstance.update();
}
} catch (err) {
console.error("Error updating dropdown:", err);
}
});
ensureSearchDocumentsVisible();
} else {
searchDocumentsContainer.style.display = "none";
}
Expand Down
85 changes: 84 additions & 1 deletion application/single_app/static/js/chat/chat-onload.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,17 @@

import { loadConversations, selectConversation, ensureConversationPresent, createNewConversation } from "./chat-conversations.js";
// Import handleDocumentSelectChange
import { loadAllDocs, populateDocumentSelectScope, handleDocumentSelectChange, loadTagsForScope, filterDocumentsBySelectedTags, setScopeFromUrlParam } from "./chat-documents.js";
import {
loadAllDocs,
populateDocumentSelectScope,
handleDocumentSelectChange,
loadTagsForScope,
filterDocumentsBySelectedTags,
setScopeFromUrlParam,
ensureSearchDocumentsVisible,
openScopeDropdown,
openTagsDropdown,
} from "./chat-documents.js";
import { getUrlParameter } from "./chat-utils.js"; // Assuming getUrlParameter is in chat-utils.js now
import { loadUserPrompts, loadGroupPrompts, initializePromptInteractions } from "./chat-prompts.js";
import { initializeModelSelector, populateModelDropdown } from "./chat-model-selector.js";
Expand All @@ -13,6 +23,68 @@ import { initializeReasoningToggle } from "./chat-reasoning.js";
import { initializeSpeechInput } from "./chat-speech-input.js";
import { initChatTutorial } from "./chat-tutorial.js";


function clearFeatureActionParam() {
const url = new URL(window.location.href);
if (!url.searchParams.has('feature_action')) {
return;
}

url.searchParams.delete('feature_action');
const nextUrl = `${url.pathname}${url.search}${url.hash}`;
window.history.replaceState({}, document.title, nextUrl);
}


function getFirstConversationId() {
const currentConversationId = window.chatConversations?.getCurrentConversationId?.();
if (currentConversationId) {
return currentConversationId;
}

const firstConversation = document.querySelector('.conversation-item[data-conversation-id]');
return firstConversation?.getAttribute('data-conversation-id') || null;
}


async function handleLatestFeatureLaunch(featureAction) {
switch (featureAction) {
case 'conversation_export': {
const conversationId = getFirstConversationId();
if (!conversationId) {
showToast('Open or start a conversation before exporting.', 'info');
return;
}

await ensureConversationPresent(conversationId);
await selectConversation(conversationId);

if (window.chatExport?.openExportWizard) {
window.chatExport.openExportWizard([conversationId], true);
} else {
showToast('Conversation export is not available right now.', 'warning');
}
return;
}
case 'multi_workspace_scope_management': {
await ensureSearchDocumentsVisible();
if (!openScopeDropdown()) {
showToast('Grounded-search scopes are not available right now.', 'info');
}
return;
}
case 'chat_document_and_tag_filtering': {
await ensureSearchDocumentsVisible();
if (!openTagsDropdown()) {
showToast('No tags are available yet for the current search scope.', 'info');
}
return;
}
default:
return;
}
}

window.addEventListener('DOMContentLoaded', async () => {
console.log("DOM Content Loaded. Starting initializations."); // Log start

Expand Down Expand Up @@ -300,6 +372,17 @@ window.addEventListener('DOMContentLoaded', async () => {
}
}

const featureAction = getUrlParameter('feature_action') || '';
if (featureAction) {
try {
await handleLatestFeatureLaunch(featureAction);
} catch (err) {
console.error('Failed to handle latest-feature launch action:', err);
} finally {
clearFeatureActionParam();
}
}

console.log("All initializations complete."); // Log end

} catch (err) {
Expand Down
35 changes: 33 additions & 2 deletions application/single_app/static/js/workspace/workspace-init.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,37 @@
// Make sure fetch functions are available globally or imported if using modules consistently
// Assuming fetchUserDocuments and fetchUserPrompts are now globally available via window.* assignments in their respective files

import { initializeTags } from './workspace-tags.js';
import { initializeTagManagement } from './workspace-tag-management.js';
import { initializeTags, setWorkspaceView } from './workspace-tags.js';
import { initializeTagManagement, showTagManagementModal } from './workspace-tag-management.js';


function clearFeatureActionParam() {
const url = new URL(window.location.href);
if (!url.searchParams.has('feature_action')) {
return;
}

url.searchParams.delete('feature_action');
window.history.replaceState({}, document.title, `${url.pathname}${url.search}${url.hash}`);
}


function handleWorkspaceFeatureAction() {
const params = new URLSearchParams(window.location.search);
const featureAction = params.get('feature_action') || '';

if (!featureAction) {
return;
}

if (featureAction === 'document_tag_system') {
showTagManagementModal();
} else if (featureAction === 'workspace_folder_view') {
setWorkspaceView('grid');
}

clearFeatureActionParam();
}

document.addEventListener('DOMContentLoaded', () => {
console.log("Workspace initializing...");
Expand Down Expand Up @@ -51,4 +80,6 @@ document.addEventListener('DOMContentLoaded', () => {
});
});

handleWorkspaceFeatureAction();

});
25 changes: 25 additions & 0 deletions application/single_app/static/js/workspace/workspace-tags.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,31 @@ function switchView(view) {
}
}


export function setWorkspaceView(view) {
const normalizedView = view === 'grid' ? 'grid' : 'list';
const listRadio = document.getElementById('docs-view-list');
const gridRadio = document.getElementById('docs-view-grid');

if (normalizedView === 'grid') {
if (gridRadio) {
gridRadio.checked = true;
}
if (listRadio) {
listRadio.checked = false;
}
} else {
if (listRadio) {
listRadio.checked = true;
}
if (gridRadio) {
gridRadio.checked = false;
}
}

switchView(normalizedView);
}

// Update sort icons in the static grid control bar
function updateGridSortIcons() {
const bar = document.getElementById('grid-controls-bar');
Expand Down
Loading
Loading