Skip to content

Comments

Added ability to export conversations#734

Open
eldong wants to merge 8 commits intoDevelopmentfrom
export-conversations
Open

Added ability to export conversations#734
eldong wants to merge 8 commits intoDevelopmentfrom
export-conversations

Conversation

@eldong
Copy link
Collaborator

@eldong eldong commented Feb 24, 2026

No description provided.

Copilot AI review requested due to automatic review settings February 24, 2026 15:31
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds a conversation export feature that allows users to export their conversations in JSON or Markdown format, with options for single-file or ZIP packaging. The export wizard provides a multi-step interface for selecting conversations, choosing formats, and downloading the results.

However, the PR contains significant unrelated changes including:

  • Retention policy settings UI for public and group workspaces
  • MIME type registration for font files
  • Custom logo image files

Changes:

  • Added conversation export backend endpoint with sanitization and active thread filtering
  • Implemented multi-step export wizard with Bootstrap modal UI
  • Added export buttons to conversation lists and sidebar with selection mode support
  • Included functional tests validating export logic and feature documentation

Reviewed changes

Copilot reviewed 15 out of 17 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
functional_tests/test_conversation_export.py Comprehensive tests for export sanitization, markdown generation, ZIP packaging, and active thread filtering
docs/explanation/features/CONVERSATION_EXPORT.md Complete feature documentation covering architecture, usage, and security
application/single_app/route_backend_conversation_export.py Backend API endpoint with conversation/message sanitization and format conversion
application/single_app/app.py Route registration for export endpoint
application/single_app/templates/chats.html Export wizard modal and button integration
application/single_app/templates/_sidebar_nav.html Export button in sidebar with compact styling
application/single_app/templates/_sidebar_short_nav.html Export button in short sidebar variant
application/single_app/static/js/chat/chat-export.js Export wizard module with multi-step UI logic
application/single_app/static/js/chat/chat-conversations.js Export button integration in main conversations list
application/single_app/static/js/chat/chat-sidebar-conversations.js Export menu item and button handlers in sidebar
application/single_app/static/css/sidebar.css Compact button styling for selection mode actions
application/single_app/templates/public_workspaces.html UNRELATED: Retention policy settings tab
application/single_app/templates/group_workspaces.html UNRELATED: Retention policy settings tab
application/single_app/static/js/public/public_workspace.js UNRELATED: Retention policy functions + broken import
application/single_app/config.py UNRELATED: MIME type registration for fonts
application/single_app/static/images/custom_logo.png UNRELATED: Custom logo image
application/single_app/static/images/custom_logo_dark.png UNRELATED: Custom logo dark mode image

Comment on lines +73 to +79
message_query = f"""
SELECT * FROM c
WHERE c.conversation_id = '{conv_id}'
ORDER BY c.timestamp ASC
"""
messages = list(cosmos_messages_container.query_items(
query=message_query,
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While not a critical security issue (since the conversation ID is validated against the database first), this query should use parameterized queries following the pattern seen elsewhere in the codebase (e.g., functions_retention_policy.py:607-612). Use WHERE c.conversation_id = @conversation_id with a parameters array like [{"name": "@conversation_id", "value": conv_id}] passed to query_items.

Suggested change
message_query = f"""
SELECT * FROM c
WHERE c.conversation_id = '{conv_id}'
ORDER BY c.timestamp ASC
"""
messages = list(cosmos_messages_container.query_items(
query=message_query,
message_query = """
SELECT * FROM c
WHERE c.conversation_id = @conversation_id
ORDER BY c.timestamp ASC
"""
messages = list(cosmos_messages_container.query_items(
query=message_query,
parameters=[{"name": "@conversation_id", "value": conv_id}],

Copilot uses AI. Check for mistakes.
Comment on lines 110 to 334
@@ -260,6 +265,73 @@ <h5>Public Prompts</h5>
<div class="d-flex align-items-center gap-3 mb-3 mt-3"><div><label class="visually-hidden">Items per page:</label><select id="public-prompts-page-size-select" class="form-select form-select-sm d-inline-block" style="width:auto;"><option value="10" selected>10</option><option value="20">20</option><option value="50">50</option></select><span class="ms-1 small text-muted">items per page</span></div><div id="public-prompts-pagination-container" class="d-flex gap-1 ms-auto"></div></div>
</div>
</div>

{% if app_settings.enable_retention_policy_public %}
<!-- Settings Tab -->
<div class="tab-pane fade" id="public-settings-tab" role="tabpanel">
<div class="card p-4 my-3">
<h5 class="mb-3"><i class="bi bi-hourglass-split me-2"></i>Retention Policy Settings</h5>
<p class="text-muted">Configure how long to keep conversations and documents in this public workspace. Items older than the specified period will be automatically deleted.</p>

<div class="alert alert-info">
<i class="bi bi-info-circle me-2"></i>
<strong>Default:</strong> You can use the organization default or set a custom retention period. Choose "No automatic deletion" to keep items indefinitely.
</div>

<div class="row g-3">
<div class="col-md-6">
<label for="public-conversation-retention-days" class="form-label">Conversation Retention</label>
<select class="form-select" id="public-conversation-retention-days" name="conversation_retention_days">
<option value="default">Using organization default</option>
<option value="none">No automatic deletion</option>
<option value="7">7 days (1 week)</option>
<option value="14">14 days (2 weeks)</option>
<option value="30">30 days (1 month)</option>
<option value="60">60 days (2 months)</option>
<option value="90">90 days (3 months)</option>
<option value="180">180 days (6 months)</option>
<option value="365">365 days (1 year)</option>
<option value="730">730 days (2 years)</option>
<option value="1095">1095 days (3 years)</option>
<option value="3650">3650 days (10 years)</option>
</select>
<small class="form-text text-muted">Conversations older than this will be automatically deleted.</small>
</div>

<div class="col-md-6">
<label for="public-document-retention-days" class="form-label">Document Retention</label>
<select class="form-select" id="public-document-retention-days" name="document_retention_days">
<option value="default">Using organization default</option>
<option value="none">No automatic deletion</option>
<option value="7">7 days (1 week)</option>
<option value="14">14 days (2 weeks)</option>
<option value="30">30 days (1 month)</option>
<option value="60">60 days (2 months)</option>
<option value="90">90 days (3 months)</option>
<option value="180">180 days (6 months)</option>
<option value="365">365 days (1 year)</option>
<option value="730">730 days (2 years)</option>
<option value="1095">1095 days (3 years)</option>
<option value="3650">3650 days (10 years)</option>
</select>
<small class="form-text text-muted">Documents older than this will be automatically deleted.</small>
</div>
</div>

<div class="mt-3">
<button type="button" class="btn btn-primary" onclick="savePublicRetentionSettings()">
<i class="bi bi-save me-1"></i>Save Retention Settings
</button>
<span id="public-retention-save-status" class="ms-3"></span>
</div>

<div class="alert alert-warning mt-3 mb-0">
<i class="bi bi-exclamation-triangle me-2"></i>
<strong>Important:</strong> Deleted conversations will be archived if archiving is enabled. All deletions are logged in activity history.
</div>
</div>
</div>
{% endif %}
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code appears to be unrelated to the conversation export feature described in the PR title. These retention policy settings for public workspaces should be in a separate PR focused on retention policy functionality, not mixed with the conversation export feature.

Copilot uses AI. Check for mistakes.
Comment on lines 281 to 826
@@ -735,6 +751,79 @@ <h5 class="mb-0 d-flex align-items-center gap-2">Group Actions</h5>
</div>
<!-- End GROUP ACTIONS TAB -->
{% endif %}

{% if app_settings.enable_retention_policy_group %}
<!-- ============= GROUP SETTINGS TAB ============= -->
<div
class="tab-pane fade"
id="group-settings-tab"
role="tabpanel"
aria-labelledby="group-settings-tab-btn"
>
<div class="card p-4 my-3">
<h5 class="mb-3"><i class="bi bi-hourglass-split me-2"></i>Retention Policy Settings</h5>
<p class="text-muted">Configure how long to keep conversations and documents in this group workspace. Items older than the specified period will be automatically deleted.</p>

<div class="alert alert-info">
<i class="bi bi-info-circle me-2"></i>
<strong>Default:</strong> You can use the organization default or set a custom retention period. Choose "No automatic deletion" to keep items indefinitely.
</div>

<div class="row g-3">
<div class="col-md-6">
<label for="group-conversation-retention-days" class="form-label">Conversation Retention</label>
<select class="form-select" id="group-conversation-retention-days" name="conversation_retention_days">
<option value="default">Using organization default</option>
<option value="none">No automatic deletion</option>
<option value="7">7 days (1 week)</option>
<option value="14">14 days (2 weeks)</option>
<option value="30">30 days (1 month)</option>
<option value="60">60 days (2 months)</option>
<option value="90">90 days (3 months)</option>
<option value="180">180 days (6 months)</option>
<option value="365">365 days (1 year)</option>
<option value="730">730 days (2 years)</option>
<option value="1095">1095 days (3 years)</option>
<option value="3650">3650 days (10 years)</option>
</select>
<small class="form-text text-muted">Conversations older than this will be automatically deleted.</small>
</div>

<div class="col-md-6">
<label for="group-document-retention-days" class="form-label">Document Retention</label>
<select class="form-select" id="group-document-retention-days" name="document_retention_days">
<option value="default">Using organization default</option>
<option value="none">No automatic deletion</option>
<option value="7">7 days (1 week)</option>
<option value="14">14 days (2 weeks)</option>
<option value="30">30 days (1 month)</option>
<option value="60">60 days (2 months)</option>
<option value="90">90 days (3 months)</option>
<option value="180">180 days (6 months)</option>
<option value="365">365 days (1 year)</option>
<option value="730">730 days (2 years)</option>
<option value="1095">1095 days (3 years)</option>
<option value="3650">3650 days (10 years)</option>
</select>
<small class="form-text text-muted">Documents older than this will be automatically deleted.</small>
</div>
</div>

<div class="mt-3">
<button type="button" class="btn btn-primary" onclick="saveGroupRetentionSettings()">
<i class="bi bi-save me-1"></i>Save Retention Settings
</button>
<span id="group-retention-save-status" class="ms-3"></span>
</div>

<div class="alert alert-warning mt-3 mb-0">
<i class="bi bi-exclamation-triangle me-2"></i>
<strong>Important:</strong> Deleted conversations will be archived if archiving is enabled. All deletions are logged in activity history.
</div>
</div>
</div>
<!-- End GROUP SETTINGS TAB -->
{% endif %}
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code appears to be unrelated to the conversation export feature described in the PR title. These retention policy settings for group workspaces should be in a separate PR focused on retention policy functionality, not mixed with the conversation export feature.

Copilot uses AI. Check for mistakes.
Comment on lines +18 to +23
# Register font MIME types so Flask serves them correctly (required for
# X-Content-Type-Options: nosniff to not block Bootstrap Icons)
mimetypes.add_type('font/woff', '.woff')
mimetypes.add_type('font/woff2', '.woff2')
mimetypes.add_type('font/ttf', '.ttf')
mimetypes.add_type('font/otf', '.otf')
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This MIME type registration code appears to be unrelated to the conversation export feature. The comment mentions "required for X-Content-Type-Options: nosniff to not block Bootstrap Icons", which is a general fix for font serving, not specific to conversation export. This should be in a separate PR or at least clearly documented as a related fix.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@paullizer paullizer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please update release_notes.md with the feature

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is great! please also update the release_notes.md

Copilot AI review requested due to automatic review settings February 24, 2026 19:57
@eldong
Copy link
Collaborator Author

eldong commented Feb 24, 2026

I updated the release notes to include the Export Conversations and Retention policy UI features.

@eldong eldong requested a review from paullizer February 24, 2026 20:00
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 18 changed files in this pull request and generated 3 comments.

@@ -1,4 +1,6 @@
// static/js/public_workspace.js
import { showToast } from "./chat/chat-toast.js";
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The import path is incorrect. The file public_workspace.js is located at static/js/public/, but it's trying to import from ./chat/chat-toast.js, which resolves to static/js/public/chat/chat-toast.js (which doesn't exist).

The correct relative import path should be ../chat/chat-toast.js to go up one directory level from public/ to js/ and then into chat/.

Suggested change
import { showToast } from "./chat/chat-toast.js";
import { showToast } from "../chat/chat-toast.js";

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +6
Version: 0.237.050
Implemented in: 0.237.050
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Version mismatch: The functional test specifies version 0.237.050, but the current version in config.py is 0.238.024. According to the coding guideline for version management (CodingGuidelineID: 1000002), functional tests must include the current version from config.py.

Update both the header comment version references to match 0.238.024.

Copilot generated this review using guidance from repository custom instructions.
## Overview
The Conversation Export feature allows users to export one or multiple conversations directly from the Chats experience. A multi-step wizard modal guides users through format selection, output packaging, and downloading the final file.

**Version Implemented:** 0.237.050
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Version mismatch: The feature documentation specifies version 0.237.050, but the current version in config.py is 0.238.024. According to the coding guideline for version management (CodingGuidelineID: 1000002), feature documentation must include the current version from config.py.

Update the version reference to match 0.238.024.

Copilot generated this review using guidance from repository custom instructions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Export Conversations via Multi Step Modal from Chat Ellipse Menu with Multi Select Support

3 participants