diff --git a/src/components/haex/pass/group/composables.ts b/src/components/haex/pass/group/composables.ts
new file mode 100644
index 0000000..2d979aa
--- /dev/null
+++ b/src/components/haex/pass/group/composables.ts
@@ -0,0 +1,24 @@
+import type { SelectHaexPasswordsGroups } from '~~/src-tauri/database/schemas/vault'
+
+export const usePasswordGroup = () => {
+ const areItemsEqual = (
+ groupA: unknown | unknown[] | null,
+ groupB: unknown | unknown[] | null,
+ ) => {
+ if (groupA === null && groupB === null) return true
+
+ if (Array.isArray(groupA) && Array.isArray(groupB)) {
+ console.log('compare object arrays', groupA, groupB)
+ if (groupA.length === groupB.length) return true
+
+ return groupA.some((group, index) => {
+ return areObjectsEqual(group, groupA[index])
+ })
+ }
+ return areObjectsEqual(groupA, groupB)
+ }
+
+ return {
+ areItemsEqual,
+ }
+}
diff --git a/src/components/haex/pass/item/keyValue.vue b/src/components/haex/pass/item/keyValue.vue
index 88f23d9..fe16792 100644
--- a/src/components/haex/pass/item/keyValue.vue
+++ b/src/components/haex/pass/item/keyValue.vue
@@ -52,7 +52,7 @@
class="btn-primary btn-outline flex-1-1 min-w-40"
>
-
{{ t('add') }}
+ {{ t('add') }}
diff --git a/src/pages/vault/[vaultId]/passwords/[[groupId]]/edit.vue b/src/pages/vault/[vaultId]/passwords/[[groupId]]/edit.vue
index b84341d..307be57 100644
--- a/src/pages/vault/[vaultId]/passwords/[[groupId]]/edit.vue
+++ b/src/pages/vault/[vaultId]/passwords/[[groupId]]/edit.vue
@@ -77,7 +77,7 @@ watch(
try {
const foundGroup = await readGroupAsync(currentGroupId.value)
if (foundGroup) {
- original.value = JSON.stringify(foundGroup)
+ original.value = JSON.parse(JSON.stringify(foundGroup))
group.value = foundGroup
}
} catch (error) {
@@ -86,22 +86,11 @@ watch(
},
{ immediate: true },
)
-/* watch(
- currentGroup,
- (n, o) => {
- console.log('currentGroup', currentGroup.value, n, o)
- original.value = JSON.stringify(currentGroup.value)
- group.value = JSON.parse(original.value)
- ignoreChanges.value = false
- },
- { immediate: true },
-) */
const read_only = ref(false)
-const hasChanges = computed(
- () => JSON.stringify(group.value) !== original.value,
-)
+const { areItemsEqual } = usePasswordGroup()
+const hasChanges = computed(() => !!!areItemsEqual(group.value, original.value))
const onClose = () => {
if (showConfirmDeleteDialog.value || showUnsavedChangesDialog.value) return
@@ -121,7 +110,7 @@ const onSaveAsync = async () => {
ignoreChanges.value = true
await updateAsync(group.value)
- await syncGroupItemsAsync(group.value.id)
+ await syncGroupItemsAsync()
add({ type: 'success', text: t('change.success') })
onClose()
} catch (error) {
@@ -141,7 +130,7 @@ const onDeleteAsync = async () => {
try {
const parentId = group.value.parentId
await deleteGroupAsync(group.value.id, inTrashGroup.value)
- await syncGroupItemsAsync(parentId)
+ await syncGroupItemsAsync()
showConfirmDeleteDialog.value = false
ignoreChanges.value = true
await navigateTo(
diff --git a/src/pages/vault/[vaultId]/passwords/[[groupId]]/index.vue b/src/pages/vault/[vaultId]/passwords/[[groupId]]/index.vue
index 0bca32b..9517037 100644
--- a/src/pages/vault/[vaultId]/passwords/[[groupId]]/index.vue
+++ b/src/pages/vault/[vaultId]/passwords/[[groupId]]/index.vue
@@ -194,7 +194,7 @@ const onPasteAsync = async () => {
[...selectedGroupItems.value],
currentGroupId.value,
)
- await syncGroupItemsAsync(currentGroupId.value)
+ await syncGroupItemsAsync()
selectedGroupItems.value = []
selectedItems.value.clear()
} catch (error) {
@@ -235,7 +235,7 @@ const onDeleteAsync = async () => {
}
}
selectedItems.value.clear()
- await syncGroupItemsAsync(currentGroupId.value)
+ await syncGroupItemsAsync()
}
const keys = useMagicKeys()
watch(keys.delete, async () => {
diff --git a/src/pages/vault/[vaultId]/passwords/[[groupId]]/item/[itemId].vue b/src/pages/vault/[vaultId]/passwords/[[groupId]]/item/[itemId].vue
index 5ca489a..1019e8d 100644
--- a/src/pages/vault/[vaultId]/passwords/[[groupId]]/item/[itemId].vue
+++ b/src/pages/vault/[vaultId]/passwords/[[groupId]]/item/[itemId].vue
@@ -1,5 +1,11 @@
+
+
+ {{ item.originalDetails }}
+
+ {{ item.details }}
+
-
-
diff --git a/src/stores/passwords/groups.ts b/src/stores/passwords/groups.ts
index 7767326..0a0a6cf 100644
--- a/src/stores/passwords/groups.ts
+++ b/src/stores/passwords/groups.ts
@@ -6,7 +6,6 @@ import {
type InsertHaexPasswordsGroups,
type SelectHaexPasswordsGroupItems,
type SelectHaexPasswordsGroups,
- type SelectHaexPasswordsItemDetails,
} from '~~/src-tauri/database/schemas/vault'
export const trashId = 'trash'
@@ -28,14 +27,6 @@ export const usePasswordGroupStore = defineStore('passwordGroupStore', () => {
currentGroupId.value ? readGroupAsync(currentGroupId.value) : null,
)
- /* const currentGroupItems = reactive<{
- items: SelectHaexPasswordsItemDetails[]
- groups: SelectHaexPasswordsGroups[]
- }>({
- items: [],
- groups: [],
- }) */
-
const selectedGroupItems = ref()
const breadCrumbs = computed(() => getParentChain(currentGroupId.value))
@@ -55,15 +46,14 @@ export const usePasswordGroupStore = defineStore('passwordGroupStore', () => {
return chain.reverse()
}
- const syncGroupItemsAsync = async (currentGroupId?: string | null) => {
- const { addNotificationAsync } = useNotificationStore()
- const { readByGroupIdAsync, syncItemsAsync } = usePasswordItemStore()
+ const syncGroupItemsAsync = async () => {
+ const { syncItemsAsync } = usePasswordItemStore()
groups.value = await readGroupsAsync()
await syncItemsAsync()
- currentGroup.value = groups.value?.find(
+ /* currentGroup.value = groups.value?.find(
(group) => group.id === currentGroupId,
- )
+ ) */
/* try {
currentGroupItems.groups =
@@ -80,7 +70,7 @@ export const usePasswordGroupStore = defineStore('passwordGroupStore', () => {
} */
}
- watch(currentGroupId, () => syncGroupItemsAsync(currentGroupId.value), {
+ watch(currentGroupId, () => syncGroupItemsAsync(), {
immediate: true,
})
@@ -90,6 +80,7 @@ export const usePasswordGroupStore = defineStore('passwordGroupStore', () => {
return {
addGroupAsync,
+ areGroupsEqual,
breadCrumbs,
createTrashIfNotExistsAsync,
currentGroup,
@@ -131,13 +122,11 @@ const addGroupAsync = async (group: Partial) => {
const readGroupAsync = async (groupId: string) => {
const { currentVault } = useVaultStore()
-
- return (
- await currentVault.drizzle
- ?.select()
- .from(haexPasswordsGroups)
- .where(eq(haexPasswordsGroups.id, groupId))
- ).at(0)
+ const group = await currentVault.drizzle.query.haexPasswordsGroups.findFirst({
+ where: eq(haexPasswordsGroups.id, groupId),
+ })
+ console.log('readGroupAsync', groupId, group)
+ return group
}
const readGroupsAsync = async (filter?: { parentId?: string | null }) => {
@@ -274,8 +263,6 @@ const insertGroupItemsAsync = async (
const targetGroup = groups.find((group) => group.id === groupdId)
- console.log('insertGroupItemsAsync', items, targetGroup)
-
for (const item of items) {
if (item.type === 'group') {
const updateGroup = groups.find((group) => group.id === item.id)
@@ -297,7 +284,7 @@ const insertGroupItemsAsync = async (
.where(eq(haexPasswordsGroupItems.itemId, item.id))
}
}
- return syncGroupItemsAsync(targetGroup?.id)
+ return syncGroupItemsAsync()
}
const createTrashIfNotExistsAsync = async () => {
@@ -340,3 +327,20 @@ const deleteGroupAsync = async (groupId: string, final: boolean = false) => {
await updateAsync({ id: groupId, parentId: trashId })
}
}
+
+const areGroupsEqual = (
+ groupA: unknown | unknown[] | null,
+ groupB: unknown | unknown[] | null,
+) => {
+ if (groupA === null && groupB === null) return true
+
+ if (Array.isArray(groupA) && Array.isArray(groupB)) {
+ console.log('compare object arrays', groupA, groupB)
+ if (groupA.length === groupB.length) return true
+
+ return groupA.some((group, index) => {
+ return areObjectsEqual(group, groupA[index])
+ })
+ }
+ return areObjectsEqual(groupA, groupB)
+}
diff --git a/src/utils/helper.ts b/src/utils/helper.ts
index aa0b093..582ba40 100644
--- a/src/utils/helper.ts
+++ b/src/utils/helper.ts
@@ -155,3 +155,78 @@ export const getContrastingTextColor = (
// Ein Wert > 186 wird oft als "hell" genug für schwarzen Text angesehen.
return luminance > 186 ? 'black' : 'white'
}
+
+/**
+ * Eine "Type Guard"-Funktion, die prüft, ob ein Wert ein Objekt (aber nicht null) ist.
+ * Wenn sie `true` zurückgibt, weiß TypeScript, dass der Wert sicher als Objekt behandelt werden kann.
+ * @param value Der zu prüfende Wert vom Typ `unknown`.
+ * @returns {boolean} `true`, wenn der Wert ein Objekt ist.
+ */
+export const isObject = (value: unknown): value is Record => {
+ return typeof value === 'object' && value !== null
+}
+
+/**
+ * Führt einen typsicheren, tiefen Vergleich (deep comparison) von zwei Werten durch.
+ * Gibt `true` zurück, wenn die Werte als gleich angesehen werden.
+ *
+ * @param valueA Der erste Wert für den Vergleich.
+ * @param valueB Der zweite Wert für den Vergleich.
+ * @returns {boolean} `true`, wenn die Werte gleich sind, andernfalls `false`.
+ */
+export const areObjectsEqual = (valueA: unknown, valueB: unknown): boolean => {
+ console.log('areObjectsEqual', valueA, valueB)
+ // 1. Schneller Check für exakt die gleiche Referenz oder primitive Gleichheit
+ if (valueA === valueB) {
+ return true
+ }
+
+ // DEINE SONDERREGEL: Behandle `null` und einen leeren String `""` als gleichwertig.
+ const areNullAndEmptyString =
+ (valueA === null && valueB === '') || (valueA === '' && valueB === null)
+
+ if (areNullAndEmptyString) {
+ return true
+ }
+
+ // 2. Nutzen der Type Guard: Wenn beide Werte keine Objekte sind,
+ // und die vorherigen Checks fehlschlugen, sind sie ungleich.
+ if (!isObject(valueA) || !isObject(valueB)) {
+ console.log('areObjectsEqual no objects', valueA, valueB)
+ return false
+ }
+
+ // Ab hier weiß TypeScript dank der Type Guard, dass valueA und valueB Objekte sind.
+
+ // 3. Holen der Schlüssel und Vergleich der Anzahl
+ const keysA = Object.keys(valueA)
+ const keysB = Object.keys(valueB)
+
+ if (keysA.length !== keysB.length) {
+ console.log('areObjectsEqual length')
+ return false
+ }
+
+ // 4. Iteration über alle Schlüssel und rekursiver Vergleich der Werte
+ for (const key of keysA) {
+ // Prüfen, ob der Schlüssel auch im zweiten Objekt überhaupt existiert
+ if (!keysB.includes(key)) {
+ console.log('areObjectsEqual keys')
+ return false
+ }
+
+ // Die Werte der Schlüssel sind wieder `unknown`, daher nutzen wir Rekursion.
+ const nestedValueA = valueA[key]
+ const nestedValueB = valueB[key]
+
+ // Wenn der rekursive Aufruf für einen der Werte `false` zurückgibt,
+ // sind die gesamten Objekte ungleich.
+ if (!areObjectsEqual(nestedValueA, nestedValueB)) {
+ console.log('areObjectsEqual nested')
+ return false
+ }
+ }
+
+ // 5. Wenn die Schleife durchläuft, sind die Objekte gleich
+ return true
+}