adding current revision information

This commit is contained in:
2026-01-02 08:29:16 -05:00
parent 789465483c
commit 920947e556
64 changed files with 5963 additions and 18 deletions
@@ -5,29 +5,95 @@
<button @click="pauseScan" :disabled="isLoading">Pause Scan</button>
<button @click="resumeScan" :disabled="isLoading">Resume Scan</button>
<p>Status: {{ status }}</p>
<hr>
<h2>Find Duplicates</h2>
<div>
<label for="threshold-slider">Similarity Threshold: {{ threshold }}</label>
<input
type="range"
id="threshold-slider"
min="0.8"
max="1.0"
step="0.01"
v-model="threshold"
/>
<button @click="findDuplicates" :disabled="isLoading">Find Duplicates</button>
</div>
<div v-if="duplicatesReport">
<h3>Duplicate Report #{{ duplicatesReport.report_id }} ({{ duplicatesReport.status }})</h3>
<button @click="deleteSelectedFiles" :disabled="selectedFiles.length === 0">Delete Selected</button>
<div v-for="group in duplicatesReport.groups" :key="group.group_id" class="duplicate-group">
<h4>Group {{ group.group_id }} (Score: {{ group.score.toFixed(4) }})</h4>
<ul>
<li v-for="file in group.files" :key="file.id">
<input type="checkbox" :value="file.filepath" v-model="selectedFiles" />
{{ file.filepath }} ({{ (file.size / 1024 / 1024).toFixed(2) }} MB)
<button @click="viewFile(file.filepath)">View</button>
</li>
</ul>
</div>
</div>
<hr>
<h2>Previous Reports</h2>
<ul>
<li v-for="report in reports" :key="report.id">
<a href="#" @click.prevent="getReport(report.id)">
Report #{{ report.id }} - {{ new Date(report.created_at).toLocaleString() }} ({{ report.status }})
</a>
</li>
</ul>
<FileViewer
v-if="fileToView"
:file-path="fileToView"
:share-name="shareName"
@close="closeViewer"
/>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { ref, onMounted, computed } from 'vue';
import FileViewer from './FileViewer.vue';
const status = ref('Idle');
const isLoading = ref(false);
const threshold = ref(0.95);
const duplicatesReport = ref(null);
const reports = ref([]);
const selectedFiles = ref([]);
const fileToView = ref(null);
const shareName = computed(() => {
if (fileToView.value) {
// This is a simplification. In a real app, you might have a more robust way
// to determine the share from the path.
if (fileToView.value.startsWith('/videos')) {
return 'isolation';
}
}
return 'media'; // Default share
});
const getStatus = async () => {
// This endpoint doesn't exist yet, but I'm adding the function in preparation.
// try {
// const response = await fetch('/api/duplicates/scan/status');
// if (response.ok) {
// const data = await response.json();
// status.value = data.status;
// } else {
// status.value = 'Error fetching status';
// }
// } catch (error) {
// status.value = 'Error fetching status';
// console.error('Error fetching status:', error);
// }
try {
const response = await fetch('/api/duplicates/scan/status');
if (response.ok) {
const data = await response.json();
status.value = data.status;
} else {
status.value = 'Error fetching status';
}
} catch (error) {
status.value = 'Error fetching status';
console.error('Error fetching status:', error);
}
};
const startScan = async () => {
@@ -71,7 +137,8 @@ const resumeScan = async () => {
const response = await fetch('/api/duplicates/scan/resume', { method: 'POST' });
if (response.ok) {
status.value = 'Scan resumed.';
} else {
}
else {
status.value = 'Error resuming scan.';
}
} catch (error) {
@@ -81,9 +148,94 @@ const resumeScan = async () => {
isLoading.value = false;
};
const getReports = async () => {
try {
const response = await fetch('/api/duplicates/reports');
if (response.ok) {
reports.value = await response.json();
} else {
console.error('Error fetching reports');
}
} catch (error) {
console.error('Error fetching reports:', error);
}
};
const getReport = async (reportId) => {
try {
const response = await fetch(`/api/duplicates/report/${reportId}`);
if (response.ok) {
duplicatesReport.value = await response.json();
selectedFiles.value = []; // Clear selection when a new report is loaded
} else {
console.error('Error fetching report');
}
} catch (error) {
console.error('Error fetching report:', error);
}
};
const findDuplicates = async () => {
isLoading.value = true;
duplicatesReport.value = null;
try {
const response = await fetch(`/api/duplicates/find?threshold=${threshold.value}`, {
method: 'POST',
});
if (response.ok) {
const data = await response.json();
if (data.report_id) {
await getReport(data.report_id);
}
await getReports(); // Refresh the list of reports
} else {
console.error('Error finding duplicates');
}
} catch (error) {
console.error('Error finding duplicates:', error);
}
isLoading.value = false;
};
const viewFile = (filePath) => {
fileToView.value = filePath;
};
const closeViewer = () => {
fileToView.value = null;
};
const deleteSelectedFiles = async () => {
if (!confirm(`Are you sure you want to delete ${selectedFiles.value.length} files?`)) {
return;
}
isLoading.value = true;
try {
const response = await fetch('/api/duplicates/files', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ filepaths: selectedFiles.value }),
});
if (response.ok) {
// Refresh the report
if (duplicatesReport.value) {
await getReport(duplicatesReport.value.report_id);
}
} else {
console.error('Error deleting files');
}
} catch (error) {
console.error('Error deleting files:', error);
}
isLoading.value = false;
};
onMounted(() => {
// getStatus();
// setInterval(getStatus, 5000); // Poll for status every 5 seconds
getStatus();
getReports();
setInterval(getStatus, 5000); // Poll for status every 5 seconds
});
</script>
@@ -91,4 +243,12 @@ onMounted(() => {
button {
margin: 5px;
}
hr {
margin: 20px 0;
}
.duplicate-group {
border: 1px solid #ccc;
padding: 10px;
margin-bottom: 10px;
}
</style>