adding current revision information
This commit is contained in:
@@ -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>
|
||||
Reference in New Issue
Block a user