mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 12:09:51 +02:00
feat: code diff
This commit is contained in:
1 parent
edce64c1bd
commit
02df1e59d8
3 files changed
+124
-51
No files matched your search
@@ -29,6 +29,7 @@
|
|||||||
"@types/semver": "^7.7.0",
|
"@types/semver": "^7.7.0",
|
||||||
"@types/three": "^0.160.0",
|
"@types/three": "^0.160.0",
|
||||||
"astro": "^5.8.0",
|
"astro": "^5.8.0",
|
||||||
|
"diff": "^8.0.2",
|
||||||
"ffi-napi": "^4.0.3",
|
"ffi-napi": "^4.0.3",
|
||||||
"fuzzysort": "^3.1.0",
|
"fuzzysort": "^3.1.0",
|
||||||
"immer": "^10.1.1",
|
"immer": "^10.1.1",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { MessageFns } from '@protos/blitz_static_profile_avatar_component';
|
import type { MessageFns } from '@protos/blitz_static_profile_avatar_component';
|
||||||
import type { Any } from '@protos/google/protobuf/any';
|
import type { Any } from '@protos/google/protobuf/any';
|
||||||
import * as protos from '@protos/index';
|
import * as protos from '@protos/index';
|
||||||
import { CommitIcon, ReaderIcon } from '@radix-ui/react-icons';
|
import { ArrowBottomRightIcon, CommitIcon } from '@radix-ui/react-icons';
|
||||||
import {
|
import {
|
||||||
Badge,
|
Badge,
|
||||||
Box,
|
Box,
|
||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
Spinner,
|
Spinner,
|
||||||
Text,
|
Text,
|
||||||
} from '@radix-ui/themes';
|
} from '@radix-ui/themes';
|
||||||
|
import { diffLines, type ChangeObject } from 'diff';
|
||||||
import { MetadataAccessor } from 'packages/core/src';
|
import { MetadataAccessor } from 'packages/core/src';
|
||||||
import type { CatalogItemAccessor } from 'packages/core/src/blitz/catalogItemAccessor';
|
import type { CatalogItemAccessor } from 'packages/core/src/blitz/catalogItemAccessor';
|
||||||
import { PageWrapper } from 'packages/website-ue/src/components/PageWrapper';
|
import { PageWrapper } from 'packages/website-ue/src/components/PageWrapper';
|
||||||
@@ -25,6 +26,7 @@ export function Page({ servers }: { servers: DiscoveryServer[] }) {
|
|||||||
const [serverB, setSeverB] = useState<DiscoveryServer | undefined>(undefined);
|
const [serverB, setSeverB] = useState<DiscoveryServer | undefined>(undefined);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [diff, setDiff] = useState<CatalogDiffEntry[] | null>(null);
|
const [diff, setDiff] = useState<CatalogDiffEntry[] | null>(null);
|
||||||
|
const [isError, setIsError] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageWrapper justify="center">
|
<PageWrapper justify="center">
|
||||||
@@ -52,12 +54,18 @@ export function Page({ servers }: { servers: DiscoveryServer[] }) {
|
|||||||
size="3"
|
size="3"
|
||||||
disabled={!serverA || !serverB}
|
disabled={!serverA || !serverB}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
setDiff(null);
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
const diff = await diffServers(serverA!.addr, serverB!.addr);
|
try {
|
||||||
|
const diff = await diffServers(serverA!.addr, serverB!.addr);
|
||||||
|
setDiff(diff);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
setIsError(true);
|
||||||
|
}
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setDiff(diff);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{loading ? <Spinner /> : <CommitIcon />}
|
{loading ? <Spinner /> : <CommitIcon />}
|
||||||
@@ -83,12 +91,25 @@ export function Page({ servers }: { servers: DiscoveryServer[] }) {
|
|||||||
</Select.Root>
|
</Select.Root>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
|
{isError && (
|
||||||
|
<Text align="center" color="red">
|
||||||
|
There was an error generating the diff, check console
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
{diff !== null && (
|
{diff !== null && (
|
||||||
<DiffDisplay
|
<>
|
||||||
diff={diff.filter(
|
{diff.length === 0 ? (
|
||||||
(entry) => entry.type !== CatalogItemDiffType.Unmodified,
|
<Text align="center" color="gray">
|
||||||
|
Branches are identical
|
||||||
|
</Text>
|
||||||
|
) : (
|
||||||
|
<DiffDisplay
|
||||||
|
diff={diff.filter(
|
||||||
|
(entry) => entry.type !== CatalogItemDiffType.Unmodified,
|
||||||
|
)}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
</>
|
||||||
)}
|
)}
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
);
|
);
|
||||||
@@ -97,43 +118,33 @@ export function Page({ servers }: { servers: DiscoveryServer[] }) {
|
|||||||
function DiffDisplay({ diff }: { diff: CatalogDiffEntry[] }) {
|
function DiffDisplay({ diff }: { diff: CatalogDiffEntry[] }) {
|
||||||
return (
|
return (
|
||||||
<Flex direction="column" gap="4">
|
<Flex direction="column" gap="4">
|
||||||
{diff.length === 0 && (
|
|
||||||
<Text align="center" color="gray">
|
|
||||||
Branches are identical
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{diff.map((entry) => (
|
{diff.map((entry) => (
|
||||||
<Flex
|
<Flex
|
||||||
|
key={entry.name}
|
||||||
direction="column"
|
direction="column"
|
||||||
gap="2"
|
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: Var('gray-3'),
|
backgroundColor: Var('gray-3'),
|
||||||
boxShadow: Var('shadow-3'),
|
boxShadow: Var('shadow-2'),
|
||||||
borderRadius: Var('radius-3'),
|
borderRadius: Var('radius-3'),
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box p="3">
|
<Box p="3">
|
||||||
<Text>
|
<Code color="gray" variant="ghost" highContrast>
|
||||||
{diffEmojis[entry.type]} {entry.name}
|
{diffEmojis[entry.type]} {entry.name}
|
||||||
</Text>
|
</Code>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Flex gap="1">
|
<Flex>
|
||||||
{(entry.type === CatalogItemDiffType.Removed ||
|
|
||||||
entry.type === CatalogItemDiffType.Unmodified) && (
|
|
||||||
<ItemDisplay item={entry.item} />
|
|
||||||
)}
|
|
||||||
{entry.type === CatalogItemDiffType.Modified && (
|
|
||||||
<ItemDisplay item={entry.a} />
|
|
||||||
)}
|
|
||||||
{(entry.type === CatalogItemDiffType.Added ||
|
{(entry.type === CatalogItemDiffType.Added ||
|
||||||
entry.type === CatalogItemDiffType.Unmodified) && (
|
entry.type === CatalogItemDiffType.Unmodified) && (
|
||||||
<ItemDisplay item={entry.item} />
|
<ItemDisplay full item={entry.item} />
|
||||||
)}
|
)}
|
||||||
{entry.type === CatalogItemDiffType.Modified && (
|
{entry.type === CatalogItemDiffType.Modified && (
|
||||||
<ItemDisplay item={entry.b} />
|
<>
|
||||||
|
<ItemDisplay item={entry.a} />
|
||||||
|
<ItemDisplay item={entry.b} diff={entry.a} />
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
@@ -142,71 +153,132 @@ function DiffDisplay({ diff }: { diff: CatalogDiffEntry[] }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ItemDisplay({ item }: { item: CatalogItemAccessor }) {
|
function ItemDisplay({
|
||||||
|
item,
|
||||||
|
full,
|
||||||
|
diff,
|
||||||
|
}: {
|
||||||
|
item: CatalogItemAccessor;
|
||||||
|
full?: boolean;
|
||||||
|
diff?: CatalogItemAccessor;
|
||||||
|
}) {
|
||||||
const entries = Object.entries(item.components);
|
const entries = Object.entries(item.components);
|
||||||
|
|
||||||
protos;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
gap="4"
|
gap="4"
|
||||||
flexGrow="1"
|
|
||||||
p="3"
|
p="3"
|
||||||
style={{
|
style={{
|
||||||
|
width: full ? '100%' : '50%',
|
||||||
backgroundColor: Var('gray-2'),
|
backgroundColor: Var('gray-2'),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{entries.length === 0 && <Text color="gray">No components</Text>}
|
{entries.length === 0 && <Text color="gray">No components</Text>}
|
||||||
|
|
||||||
{entries.map(([key, value]) => (
|
{entries.map(([key, value]) => (
|
||||||
<ComponentDisplay key={key} name={key} value={value} />
|
<ComponentDisplay
|
||||||
|
key={key}
|
||||||
|
name={key}
|
||||||
|
value={value}
|
||||||
|
diff={diff?.components[key]}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ComponentDisplay({ name, value }: { name: string; value: Any }) {
|
function ComponentDisplay({
|
||||||
const [code, setCode] = useState<string | null>(null);
|
name,
|
||||||
|
value,
|
||||||
|
diff,
|
||||||
|
}: {
|
||||||
|
name: string;
|
||||||
|
value: Any;
|
||||||
|
diff?: Any;
|
||||||
|
}) {
|
||||||
|
const [code, setCode] = useState<string | ChangeObject<string>[] | null>(
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex direction="column" gap="1">
|
<Flex direction="column" gap="2">
|
||||||
<Flex gap="2" align="center">
|
<Flex gap="2" align="center" maxWidth="100%" overflow="hidden">
|
||||||
<IconButton
|
<IconButton
|
||||||
size="1"
|
size="1"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
if (code !== null) return setCode(null);
|
||||||
|
|
||||||
const messageName = value.type_url
|
const messageName = value.type_url
|
||||||
.slice(2)
|
.slice(2)
|
||||||
.split('.')
|
.split('.')
|
||||||
.slice(1)
|
.slice(1)
|
||||||
.join('.');
|
.join('.');
|
||||||
const json = (
|
const Message = protos[
|
||||||
protos[messageName as keyof typeof protos] as MessageFns<any>
|
messageName as keyof typeof protos
|
||||||
).decode(value.value);
|
] as MessageFns<any>;
|
||||||
|
const json = Message.decode(value.value);
|
||||||
|
|
||||||
setCode(JSON.stringify(json, null, 2));
|
if (diff === undefined) {
|
||||||
|
setCode(JSON.stringify(json, null, 2));
|
||||||
|
} else {
|
||||||
|
const b = JSON.stringify(json, null, 2);
|
||||||
|
const a = JSON.stringify(Message.decode(diff.value), null, 2);
|
||||||
|
|
||||||
|
setCode(diffLines(a, b));
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ReaderIcon />
|
<ArrowBottomRightIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|
||||||
<Code color="gray" highContrast variant="ghost">
|
<Code color="gray" variant="ghost">
|
||||||
{name}
|
{name}
|
||||||
</Code>
|
</Code>
|
||||||
<Badge>{value.value.length.toLocaleString()}B</Badge>
|
<Badge color="gray" variant="outline">
|
||||||
|
{value.value.length.toLocaleString()}B
|
||||||
|
</Badge>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
{code !== null && (
|
{code !== null && (
|
||||||
<Code
|
<Flex
|
||||||
ml="4"
|
direction="column"
|
||||||
size="1"
|
ml="5"
|
||||||
color="gray"
|
p="2"
|
||||||
highContrast
|
style={{
|
||||||
style={{ whiteSpace: 'pre' }}
|
overflowX: 'auto',
|
||||||
|
backgroundColor: Var('gray-1'),
|
||||||
|
borderRadius: Var('radius-2'),
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{code}
|
{typeof code === 'string' ? (
|
||||||
</Code>
|
<Code
|
||||||
|
size="1"
|
||||||
|
color="gray"
|
||||||
|
variant="ghost"
|
||||||
|
highContrast
|
||||||
|
style={{ borderRadius: 0, whiteSpace: 'pre' }}
|
||||||
|
children={code}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
code.map((line) => {
|
||||||
|
const modified = line.added || line.removed;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Code
|
||||||
|
size="1"
|
||||||
|
color={line.added ? 'green' : line.removed ? 'red' : 'gray'}
|
||||||
|
variant={modified ? 'soft' : 'ghost'}
|
||||||
|
highContrast={!modified}
|
||||||
|
style={{ borderRadius: 0, whiteSpace: 'pre' }}
|
||||||
|
key={line.value}
|
||||||
|
children={line.value}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in new issue
Block a user