-
{{ entry.aspect }}
+
+ {{ entry.aspect }}
+
+
+
+ mdi-eye-off-outline
+
+
+
+
Examples:
@@ -365,6 +413,29 @@ export default {
const architecturalRoleValue = computed(() => metadataValue.value?.architecturalRole || '')
const activeCategoryId = ref('')
const applicabilityFilter = ref('all')
+ const entrySearch = ref('')
+ const entrySort = ref('')
+
+ const hiddenEntries = computed(() =>
+ props.questionnaireId ? store.getQuestionnaireHiddenEntries(props.questionnaireId) : new Set()
+ )
+
+ function hideEntry(entryId) {
+ if (!props.questionnaireId) return
+ const updated = new Set([...hiddenEntries.value, entryId])
+ store.setQuestionnaireHiddenEntries(props.questionnaireId, updated)
+ }
+
+ function showAllEntries() {
+ if (!props.questionnaireId) return
+ store.setQuestionnaireHiddenEntries(props.questionnaireId, new Set())
+ }
+
+ function cycleSort() {
+ if (entrySort.value === '') entrySort.value = 'asc'
+ else if (entrySort.value === 'asc') entrySort.value = 'desc'
+ else entrySort.value = ''
+ }
function toArray(value) {
if (!value) return []
@@ -417,16 +488,39 @@ export default {
const visibleEntries = computed(() => {
const entries = Array.isArray(currentCategory.value.entries) ? currentCategory.value.entries : []
- const filteredByMetadata = entries.filter((entry) => appliesToMatches(entry.appliesTo, metadataValue.value))
-
- if (applicabilityFilter.value === 'all') {
- return filteredByMetadata
+ let result = entries.filter((entry) => appliesToMatches(entry.appliesTo, metadataValue.value))
+
+ if (applicabilityFilter.value !== 'all') {
+ result = result.filter((entry) => {
+ const entryApplicability = entry.applicability || 'applicable'
+ return entryApplicability === applicabilityFilter.value
+ })
}
-
- return filteredByMetadata.filter((entry) => {
- const entryApplicability = entry.applicability || 'applicable'
- return entryApplicability === applicabilityFilter.value
- })
+
+ if (entrySearch.value && entrySearch.value.trim()) {
+ const q = entrySearch.value.trim().toLowerCase()
+ result = result.filter((entry) =>
+ (entry.aspect || '').toLowerCase().includes(q) ||
+ (entry.description || '').toLowerCase().includes(q)
+ )
+ }
+
+ if (entrySort.value === 'asc') {
+ result = [...result].sort((a, b) => (a.aspect || '').localeCompare(b.aspect || ''))
+ } else if (entrySort.value === 'desc') {
+ result = [...result].sort((a, b) => (b.aspect || '').localeCompare(a.aspect || ''))
+ }
+
+ return result.filter((entry) => !hiddenEntries.value.has(entry.id))
+ })
+
+ const currentCategoryHiddenCount = computed(() => {
+ const entries = Array.isArray(currentCategory.value.entries) ? currentCategory.value.entries : []
+ let result = entries.filter((entry) => appliesToMatches(entry.appliesTo, metadataValue.value))
+ if (applicabilityFilter.value !== 'all') {
+ result = result.filter((entry) => (entry.applicability || 'applicable') === applicabilityFilter.value)
+ }
+ return result.filter((entry) => hiddenEntries.value.has(entry.id)).length
})
const applicabilityFilterOptions = computed(() => {
@@ -460,6 +554,8 @@ export default {
function selectCategory(id) {
activeCategoryId.value = id
+ entrySearch.value = ''
+ entrySort.value = ''
scrollToTop()
}
@@ -495,6 +591,8 @@ export default {
const idx = visibleCategories.value.findIndex((category) => category.id === activeCategoryId.value)
if (idx < visibleCategories.value.length - 1) {
activeCategoryId.value = visibleCategories.value[idx + 1].id
+ entrySearch.value = ''
+ entrySort.value = ''
scrollToTop()
}
}
@@ -503,6 +601,8 @@ export default {
const idx = visibleCategories.value.findIndex((category) => category.id === activeCategoryId.value)
if (idx > 0) {
activeCategoryId.value = visibleCategories.value[idx - 1].id
+ entrySearch.value = ''
+ entrySort.value = ''
scrollToTop()
}
}
@@ -595,7 +695,13 @@ export default {
answerTypeOptions,
isReference,
parentProject,
- toggleReference
+ toggleReference,
+ entrySearch,
+ entrySort,
+ cycleSort,
+ hideEntry,
+ showAllEntries,
+ currentCategoryHiddenCount
}
}
}
@@ -612,6 +718,32 @@ export default {
resize: vertical;
}
+.entry-title-row {
+ flex-wrap: nowrap;
+}
+
+.entry-hide-btn {
+ opacity: 0;
+ transition: opacity 0.12s;
+ flex-shrink: 0;
+}
+.entry-title-row:hover .entry-hide-btn {
+ opacity: 0.5;
+}
+.entry-hide-btn:hover {
+ opacity: 1 !important;
+}
+
+.hidden-entries-chip {
+ cursor: pointer;
+ opacity: 0.4;
+ transition: opacity 0.15s;
+ font-size: 11px !important;
+}
+.hidden-entries-chip:hover {
+ opacity: 0.85;
+}
+
.entry-highlighted {
animation: entry-flash 2s ease-out;
border-radius: 4px;
diff --git a/src/stores/workspaceStore.js b/src/stores/workspaceStore.js
index 7f1a72f..0d6a355 100644
--- a/src/stores/workspaceStore.js
+++ b/src/stores/workspaceStore.js
@@ -43,6 +43,7 @@ export const useWorkspaceStore = defineStore('workspace', () => {
const autoSaveStarted = ref(false)
const pendingNavigation = ref(null) // { questionnaireId, categoryId, entryId } | null
const workspaceDirNeeded = ref(false)
+ const questionnaireHiddenEntries = ref({}) // Record
const activeQuestionnaire = computed(() => {
return workspace.value.questionnaires.find((item) => item.id === activeQuestionnaireId.value) || null
@@ -94,6 +95,7 @@ export const useWorkspaceStore = defineStore('workspace', () => {
openQuestionnaireIds.value = []
activeWorkspaceTabId.value = ''
openProjectSummaryIds.value = []
+ questionnaireHiddenEntries.value = data.questionnaireHiddenEntries || {}
hydrateLastSaved(data.timestamp)
return true
}
@@ -104,6 +106,7 @@ export const useWorkspaceStore = defineStore('workspace', () => {
openQuestionnaireIds.value = []
activeWorkspaceTabId.value = ''
openProjectSummaryIds.value = []
+ questionnaireHiddenEntries.value = {}
hydrateLastSaved(data.timestamp)
return true
}
@@ -170,7 +173,7 @@ export const useWorkspaceStore = defineStore('workspace', () => {
if (autoSaveStarted.value) return
autoSaveStarted.value = true
watch(
- () => [workspace.value, activeQuestionnaireId.value, openQuestionnaireIds.value, activeWorkspaceTabId.value, openProjectSummaryIds.value],
+ () => [workspace.value, activeQuestionnaireId.value, openQuestionnaireIds.value, activeWorkspaceTabId.value, openProjectSummaryIds.value, questionnaireHiddenEntries.value],
() => {
clearTimeout(persistDebounceTimer)
persistDebounceTimer = setTimeout(() => persist(), 500)
@@ -187,7 +190,8 @@ export const useWorkspaceStore = defineStore('workspace', () => {
activeQuestionnaireId: activeQuestionnaireId.value,
openQuestionnaireIds: openQuestionnaireIds.value,
activeWorkspaceTabId: activeWorkspaceTabId.value,
- openProjectSummaryIds: openProjectSummaryIds.value
+ openProjectSummaryIds: openProjectSummaryIds.value,
+ questionnaireHiddenEntries: questionnaireHiddenEntries.value
}
if (window.electronAPI) {
@@ -246,6 +250,17 @@ export const useWorkspaceStore = defineStore('workspace', () => {
pendingNavigation.value = null
}
+ function getQuestionnaireHiddenEntries(questionnaireId) {
+ return new Set(questionnaireHiddenEntries.value[questionnaireId] || [])
+ }
+
+ function setQuestionnaireHiddenEntries(questionnaireId, entryIdSet) {
+ questionnaireHiddenEntries.value = {
+ ...questionnaireHiddenEntries.value,
+ [questionnaireId]: [...entryIdSet]
+ }
+ }
+
function openProjectSummary(projectId) {
const project = workspace.value.projects.find((item) => item.id === projectId)
if (!project) return
@@ -853,6 +868,8 @@ export const useWorkspaceStore = defineStore('workspace', () => {
setReferenceQuestionnaire,
pendingNavigation,
navigateToEntry,
- clearPendingNavigation
+ clearPendingNavigation,
+ getQuestionnaireHiddenEntries,
+ setQuestionnaireHiddenEntries
}
})