datajunction-ui
Version:
DataJunction UI
210 lines (199 loc) • 6.6 kB
JSX
import { useContext, useEffect, useState } from 'react';
import * as React from 'react';
import { diffLines, formatLines } from 'unidiff';
import { parseDiff, Diff, Hunk } from 'react-diff-view';
import { useParams } from 'react-router-dom';
import DJClientContext from '../../providers/djclient';
import NamespaceHeader from '../../components/NamespaceHeader';
import { labelize } from '../../../utils/form';
import DiffIcon from '../../icons/DiffIcon';
import { Light as SyntaxHighlighter } from 'react-syntax-highlighter';
import foundation from 'react-syntax-highlighter/dist/esm/styles/hljs/foundation';
import sql from 'react-syntax-highlighter/dist/cjs/languages/hljs/sql';
SyntaxHighlighter.registerLanguage('sql', sql);
foundation.hljs['padding'] = '2rem';
export default function RevisionDiff() {
const djClient = useContext(DJClientContext).DataJunctionAPI;
const [revisions, setRevisions] = useState([]);
const { name, revision } = useParams();
useEffect(() => {
const fetchData = async () => {
const revisions = await djClient.revisions(name);
setRevisions(revisions);
};
fetchData().catch(console.error);
}, [djClient, name]);
const thisRevision = revisions
.map((rev, idx) => [idx, rev])
.filter((rev, idx) => {
return rev[1].version === revision;
});
const prevRevision = revisions.filter(
(rev, idx) => idx + 1 === thisRevision[0][0],
);
const EMPTY_HUNKS = [];
const revisionDiff = (older, newer) => {
const diffObj = {};
const fields = [
'display_name',
'version',
'query',
'mode',
'status',
'description',
'columns',
// 'catalog',
'schema',
'table',
'updated_at',
];
if (older) {
for (const key of fields) {
if (older[key] && (key !== 'columns' || older.type === 'cube')) {
diffObj[key] = {};
diffObj[key].diffText = formatLines(
diffLines(
older
? key === 'columns'
? older[key].map(col => col.name).join('\n')
: older[key].toString()
: '',
newer
? key === 'columns'
? newer[key].map(col => col.name).join('\n')
: newer[key].toString()
: '',
),
{
context: 5000,
},
);
const [diff] = parseDiff(diffObj[key].diffText, {
nearbySequences: 'zip',
});
diffObj[key].diff = diff;
}
}
}
return diffObj;
};
const diffObjects = revisionDiff(
prevRevision[0],
thisRevision[0] ? thisRevision[0][1] : thisRevision[0],
);
return (
<div className="node__header">
<NamespaceHeader
namespace={(prevRevision[0] ? prevRevision[0].name : '')
.split('.')
.slice(0, -1)
.join('.')}
/>
<div className="card">
<div className="card-header">
<h3
className="card-title align-items-start flex-column"
style={{ display: 'inline-block' }}
>
<span
className="card-label fw-bold text-gray-800"
role="dialog"
aria-hidden="false"
aria-label="DisplayName"
>
<a
href={'/nodes/' + prevRevision[0]?.name}
className=""
role="dialog"
aria-hidden="false"
aria-label="NodeName"
>
{prevRevision[0]?.name}
</a>{' '}
<span
className={
'node_type__' + prevRevision[0]?.type + ' badge node_type'
}
role="dialog"
aria-hidden="false"
aria-label="NodeType"
>
{prevRevision[0]?.type}
</span>
</span>
</h3>
<div>
<span
className="rounded-pill badge version"
style={{ marginLeft: '0.5rem', fontSize: '16px' }}
>
{prevRevision[0]?.version}
</span>
<DiffIcon />
<span
className="rounded-pill badge version"
style={{ marginLeft: '0.3rem', fontSize: '16px' }}
>
{thisRevision[0] ? thisRevision[0][1].version : ''}
</span>{' '}
</div>
{Object.keys(diffObjects).map(field => {
return (
<div className="diff" aria-label={'DiffView'} role={'gridcell'}>
<h4>
{labelize(field)}{' '}
<small className="no-change-banner">
{diffObjects[field]?.diff.hunks.length > 0
? ''
: 'no change'}
</small>
</h4>
{diffObjects[field]?.diff.hunks.length > 0 ? (
<Diff
viewType="split"
diffType=""
hunks={diffObjects[field]?.diff.hunks || EMPTY_HUNKS}
tokens={diffObjects[field]?.tokens}
>
{hunks =>
hunks.map(hunk => <Hunk key={hunk.content} hunk={hunk} />)
}
</Diff>
) : (
<div className="no-change">
{prevRevision[0] ? (
field === 'query' ? (
<>
<SyntaxHighlighter
language="sql"
style={foundation}
wrapLongLines={true}
>
{prevRevision[0].query}
</SyntaxHighlighter>
</>
) : field === 'columns' ? (
<div>
{prevRevision[0][field].map(col => (
<>
{col.name}
<br />
</>
))}
</div>
) : (
prevRevision[0][field].toString()
)
) : (
''
)}
</div>
)}
</div>
);
})}
</div>
</div>
</div>
);
}