diff options
author | 2023-04-22 00:49:03 +0200 | |
---|---|---|
committer | 2023-04-23 15:24:20 +0200 | |
commit | 362f2fa280fdab210074e9a7e01dde6187924d29 (patch) | |
tree | 2a17c13e1db19e0b244cda22eabf8e107218f6b9 /src/tools/json-diff/diff-viewer | |
parent | 61ece2387f7061d67177ee41c35db572ffeb84a7 (diff) | |
download | it-tools-362f2fa280fdab210074e9a7e01dde6187924d29.tar.gz it-tools-362f2fa280fdab210074e9a7e01dde6187924d29.tar.zst it-tools-362f2fa280fdab210074e9a7e01dde6187924d29.zip |
feat(new-tool): diff of two json objects
Diffstat (limited to 'src/tools/json-diff/diff-viewer')
-rw-r--r-- | src/tools/json-diff/diff-viewer/diff-viewer.models.tsx | 119 | ||||
-rw-r--r-- | src/tools/json-diff/diff-viewer/diff-viewer.vue | 110 |
2 files changed, 229 insertions, 0 deletions
diff --git a/src/tools/json-diff/diff-viewer/diff-viewer.models.tsx b/src/tools/json-diff/diff-viewer/diff-viewer.models.tsx new file mode 100644 index 0000000..5a19feb --- /dev/null +++ b/src/tools/json-diff/diff-viewer/diff-viewer.models.tsx @@ -0,0 +1,119 @@ +import _ from 'lodash'; +import { useCopy } from '@/composable/copy'; +import type { Difference, ArrayDifference, ObjectDifference } from '../json-diff.types'; + +export const DiffRootViewer = ({ diff }: { diff: Difference }) => { + return ( + <div class={'diffs-viewer'}> + <ul>{DiffViewer({ diff, showKeys: false })}</ul> + </div> + ); +}; + +const DiffViewer = ({ diff, showKeys = true }: { diff: Difference; showKeys?: boolean }) => { + const { type, status } = diff; + + if (status === 'updated') { + return ComparisonViewer({ diff, showKeys }); + } + + if (type === 'array') { + return ChildrenViewer({ diff, showKeys, showChildrenKeys: false, openTag: '[', closeTag: ']' }); + } + + if (type === 'object') { + return ChildrenViewer({ diff, showKeys, openTag: '{', closeTag: '}' }); + } + + return LineDiffViewer({ diff, showKeys }); +}; + +const LineDiffViewer = ({ diff, showKeys }: { diff: Difference; showKeys?: boolean }) => { + const { value, key, status, oldValue } = diff; + const valueToDisplay = status === 'removed' ? oldValue : value; + + return ( + <li> + <span class={[status, 'result']}> + {showKeys && ( + <> + <span class={'key'}>{key}</span> + {': '} + </> + )} + {Value({ value: valueToDisplay, status })} + </span> + , + </li> + ); +}; + +const ComparisonViewer = ({ diff, showKeys }: { diff: Difference; showKeys?: boolean }) => { + const { value, key, oldValue } = diff; + + return ( + <li class={'updated-line'}> + {showKeys && ( + <> + <span class={'key'}>{key}</span> + {': '} + </> + )} + {Value({ value: oldValue, status: 'removed' })} + {Value({ value, status: 'added' })}, + </li> + ); +}; + +const ChildrenViewer = ({ + diff, + openTag, + closeTag, + showKeys, + showChildrenKeys = true, +}: { + diff: ArrayDifference | ObjectDifference; + showKeys: boolean; + showChildrenKeys?: boolean; + openTag: string; + closeTag: string; +}) => { + const { children, key, status, type } = diff; + + return ( + <li> + <div class={[type, status]} style={{ display: 'inline-block' }}> + {showKeys && ( + <> + <span class={'key'}>{key}</span> + {': '} + </> + )} + + {openTag} + {children.length > 0 && <ul>{children.map((diff) => DiffViewer({ diff, showKeys: showChildrenKeys }))}</ul>} + {closeTag + ','} + </div> + </li> + ); +}; + +function formatValue(value: unknown) { + if (_.isNull(value)) { + return 'null'; + } + + return JSON.stringify(value); +} + +const Value = ({ value, status }: { value: unknown; status: string }) => { + const formatedValue = formatValue(value); + + const { copy } = useCopy({ source: formatedValue }); + + return ( + <span class={['value', status]} onClick={copy}> + {formatedValue} + </span> + ); +}; diff --git a/src/tools/json-diff/diff-viewer/diff-viewer.vue b/src/tools/json-diff/diff-viewer/diff-viewer.vue new file mode 100644 index 0000000..c77d407 --- /dev/null +++ b/src/tools/json-diff/diff-viewer/diff-viewer.vue @@ -0,0 +1,110 @@ +<template> + <div v-if="showResults"> + <n-space justify="center"> + <n-form-item label="Only show differences" label-placement="left"> + <n-switch v-model:value="onlyShowDifferences" /> + </n-form-item> + </n-space> + + <c-card data-test-id="diff-result"> + <n-text v-if="jsonAreTheSame" depth="3" block text-center italic> The provided JSONs are the same </n-text> + <diff-root-viewer v-else :diff="result" /> + </c-card> + </div> +</template> + +<script lang="ts" setup> +import { useAppTheme } from '@/ui/theme/themes'; +import _ from 'lodash'; +import { DiffRootViewer } from './diff-viewer.models'; +import { diff } from '../json-diff.models'; + +const onlyShowDifferences = ref(false); +const props = defineProps<{ leftJson: unknown; rightJson: unknown }>(); +const { leftJson, rightJson } = toRefs(props); +const appTheme = useAppTheme(); + +const result = computed(() => + diff(leftJson.value, rightJson.value, { onlyShowDifferences: onlyShowDifferences.value }), +); + +const jsonAreTheSame = computed(() => _.isEqual(leftJson.value, rightJson.value)); +const showResults = computed(() => !_.isUndefined(leftJson.value) && !_.isUndefined(rightJson.value)); +</script> + +<style lang="less" scoped> +::v-deep(.diffs-viewer) { + color: v-bind('appTheme.text.mutedColor'); + + & > ul { + padding-left: 0 !important; + } + + ul { + list-style: none; + padding-left: 20px; + margin: 0; + + li { + .updated-line { + padding: 3px 0; + } + + .result, + .array, + .object, + .value { + &:not(:last-child) { + margin-right: 4px; + } + + &.added { + padding: 3px 5px; + border-radius: 4px; + background-color: v-bind('appTheme.success.colorFaded'); + color: v-bind('appTheme.success.color'); + .key { + color: inherit; + } + } + + &.removed { + padding: 3px 5px; + border-radius: 4px; + background-color: v-bind('appTheme.error.colorFaded'); + color: v-bind('appTheme.error.color'); + + .key { + color: inherit; + } + } + } + + .value { + cursor: pointer; + border: 1px solid transparent; + transition: border-color 0.2s ease-in-out; + + &.added:hover { + border-color: v-bind('appTheme.success.color'); + } + + &.removed:hover { + border-color: v-bind('appTheme.error.color'); + } + } + + .added .added, + .removed .removed { + background-color: transparent; + color: inherit; + } + + .key { + font-weight: 500; + color: v-bind('appTheme.text.baseColor'); + } + } + } +} +</style> |