Measure what's left of upstream; drop two unused components #117
No files matched your search
Generated
-32
@@ -18,7 +18,6 @@
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.24",
|
||||
"@radix-ui/react-label": "^2.1.15",
|
||||
"@radix-ui/react-popover": "^1.1.23",
|
||||
"@radix-ui/react-scroll-area": "^1.2.18",
|
||||
"@radix-ui/react-select": "^2.3.7",
|
||||
"@radix-ui/react-separator": "^1.1.15",
|
||||
"@radix-ui/react-slot": "^1.3.3",
|
||||
@@ -1286,37 +1285,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-scroll-area": {
|
||||
"version": "1.2.18",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.18.tgz",
|
||||
"integrity": "sha512-Zn5Cd171wxsO3Dfg8HaW6RifTb9CYTKQJHs/G4+LN1GfmJpaQMZQyQxMprVPHpaz7QY4l9BxK2JwQuzHsXC8nA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/number": "1.1.3",
|
||||
"@radix-ui/primitive": "1.1.7",
|
||||
"@radix-ui/react-compose-refs": "1.1.5",
|
||||
"@radix-ui/react-context": "1.2.2",
|
||||
"@radix-ui/react-direction": "1.1.4",
|
||||
"@radix-ui/react-presence": "1.1.10",
|
||||
"@radix-ui/react-primitive": "2.1.10",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.4",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-select": {
|
||||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.3.7.tgz",
|
||||
|
||||
+2
-2
@@ -18,7 +18,8 @@
|
||||
"i18n:check": "node tools/i18n-extract.mjs --check",
|
||||
"notice:check": "node tools/notice-check.mjs",
|
||||
"notice:fix": "node tools/notice-check.mjs --fix",
|
||||
"manual": "node tools/build-manual.mjs --schema ../inbuxa-server/resources/schema/schema.json.gz --out ../inbuxa.org/docs-site/docs/reference"
|
||||
"manual": "node tools/build-manual.mjs --schema ../inbuxa-server/resources/schema/schema.json.gz --out ../inbuxa.org/docs-site/docs/reference",
|
||||
"divergence": "node tools/divergence.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@daypicker/react": "^10.0.1",
|
||||
@@ -31,7 +32,6 @@
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.24",
|
||||
"@radix-ui/react-label": "^2.1.15",
|
||||
"@radix-ui/react-popover": "^1.1.23",
|
||||
"@radix-ui/react-scroll-area": "^1.2.18",
|
||||
"@radix-ui/react-select": "^2.3.7",
|
||||
"@radix-ui/react-separator": "^1.1.15",
|
||||
"@radix-ui/react-slot": "^1.3.3",
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
* SPDX-FileCopyrightText: 2026 Coffey Labs LLC
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*
|
||||
* Modified by Coffey Labs in 2026 for INBUXA.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import { Tooltip as RechartsTooltip } from 'recharts';
|
||||
import type { TooltipPayload } from 'recharts/types/state/tooltipSlice';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
export const CHART_COLORS = [
|
||||
'var(--chart-1)',
|
||||
'var(--chart-2)',
|
||||
'var(--chart-3)',
|
||||
'var(--chart-4)',
|
||||
'var(--chart-5)',
|
||||
] as const;
|
||||
|
||||
export function getChartColor(index: number): string {
|
||||
return CHART_COLORS[index % CHART_COLORS.length];
|
||||
}
|
||||
|
||||
export function ChartContainer({ children, className }: { children: React.ReactNode; className?: string }) {
|
||||
return <div className={cn('w-full', className)}>{children}</div>;
|
||||
}
|
||||
|
||||
export function ChartTooltipContent({
|
||||
active,
|
||||
payload,
|
||||
label,
|
||||
formatter,
|
||||
}: {
|
||||
active?: boolean;
|
||||
payload?: TooltipPayload;
|
||||
label?: string;
|
||||
formatter?: (value: number) => string;
|
||||
}) {
|
||||
if (!active || !payload?.length) return null;
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border bg-background p-2 shadow-md">
|
||||
{label && <p className="mb-1 text-xs text-muted-foreground">{label}</p>}
|
||||
{payload.map((entry, i) => (
|
||||
<div key={i} className="flex items-center gap-2 text-sm">
|
||||
<span
|
||||
className="h-2.5 w-2.5 shrink-0 rounded-full"
|
||||
style={{ backgroundColor: entry.color ?? 'currentColor' }}
|
||||
/>
|
||||
<span className="text-muted-foreground">{entry.name ?? ''}</span>
|
||||
<span className="ml-auto font-medium">
|
||||
{formatter && typeof entry.value === 'number' ? formatter(entry.value) : String(entry.value ?? '')}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { RechartsTooltip };
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const ScrollArea = React.forwardRef<
|
||||
React.ComponentRef<typeof ScrollAreaPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.Root ref={ref} className={cn('relative overflow-hidden', className)} {...props}>
|
||||
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">{children}</ScrollAreaPrimitive.Viewport>
|
||||
<ScrollBar />
|
||||
<ScrollAreaPrimitive.Corner />
|
||||
</ScrollAreaPrimitive.Root>
|
||||
));
|
||||
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
|
||||
|
||||
const ScrollBar = React.forwardRef<
|
||||
React.ComponentRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
>(({ className, orientation = 'vertical', ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
||||
ref={ref}
|
||||
orientation={orientation}
|
||||
className={cn(
|
||||
'flex touch-none select-none transition-colors',
|
||||
orientation === 'vertical' && 'h-full w-2.5 border-l border-l-transparent p-[1px]',
|
||||
orientation === 'horizontal' && 'h-2.5 flex-col border-t border-t-transparent p-[1px]',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
|
||||
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
));
|
||||
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
|
||||
|
||||
export { ScrollArea, ScrollBar };
|
||||
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env node
|
||||
// SPDX-FileCopyrightText: 2026 Coffey Labs LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
/**
|
||||
* inbuxa: how much of the console is still upstream's, measured against
|
||||
* BASE, the upstream release this fork started from. The console no longer
|
||||
* takes upstream changes, and is being rewritten until none of upstream's
|
||||
* code is left (inbuxa-drafts/specs/console-rewrite-plan.md); each PR of that
|
||||
* work states how far it moved these numbers.
|
||||
*
|
||||
* node tools/divergence.mjs the summary, for HEAD
|
||||
* node tools/divergence.mjs <ref> the summary, for another commit
|
||||
* node tools/divergence.mjs --files also each file with upstream lines left
|
||||
*
|
||||
* Lines are counted from git's diff, without package-lock.json or binary
|
||||
* files. "Not upstream's" is every line but upstream's: ours, and third-party
|
||||
* code such as components taken from shadcn/ui.
|
||||
*
|
||||
* A file whose header named Stalwart Labs at BASE and no longer does has been
|
||||
* rewritten, and none of its lines count as upstream's: the header only
|
||||
* changes once the rewrite is done. A rewrite still shares some lines with
|
||||
* upstream's file (blank lines, imports, closing brackets, and class lists
|
||||
* both took from shadcn/ui), so the summary prints how many, to keep the
|
||||
* claim checkable.
|
||||
*/
|
||||
import { execFileSync } from 'node:child_process';
|
||||
|
||||
// Upstream's web interface v1.0.11, the release this fork started from.
|
||||
const BASE = process.env.DIVERGENCE_BASE || 'dc462b137fbee9c2193946a6db554ff20bcc9b07';
|
||||
const EXCLUDE = [':!package-lock.json'];
|
||||
const DUAL_HEADER = '^\\s*(\\*|//|#)\\s*SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL';
|
||||
const UPSTREAM_HOLDER = 'SPDX-FileCopyrightText:.*Stalwart Labs';
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const showFiles = args.includes('--files');
|
||||
const ref = args.find((a) => !a.startsWith('--')) ?? 'HEAD';
|
||||
|
||||
const git = (...a) => execFileSync('git', a, { encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
|
||||
const empty = git('hash-object', '-t', 'tree', '/dev/null').trim();
|
||||
|
||||
/** Per-file [added, deleted] between two trees, binary files left out. */
|
||||
function numstat(from, to) {
|
||||
const out = new Map();
|
||||
for (const line of git('diff', '--numstat', '--no-renames', from, to, '--', '.', ...EXCLUDE).split('\n')) {
|
||||
const [a, d, path] = line.split('\t');
|
||||
if (!path || a === '-') continue;
|
||||
out.set(path, [Number(a), Number(d)]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
const sum = (m, i) => [...m.values()].reduce((n, v) => n + v[i], 0);
|
||||
|
||||
/** Files at `at` whose lines match `pattern`, as a set of paths. */
|
||||
function grepFiles(pattern, at) {
|
||||
try {
|
||||
return new Set(
|
||||
git('grep', '-l', '-E', pattern, at, '--')
|
||||
.split('\n')
|
||||
.filter(Boolean)
|
||||
.map((l) => l.slice(at.length + 1)),
|
||||
);
|
||||
} catch {
|
||||
// git grep exits 1 when nothing matches
|
||||
return new Set();
|
||||
}
|
||||
}
|
||||
|
||||
const baseFiles = numstat(empty, BASE);
|
||||
const changes = numstat(BASE, ref);
|
||||
const forkLines = sum(numstat(empty, ref), 0);
|
||||
const upstreamLines = sum(baseFiles, 0);
|
||||
|
||||
const headed = grepFiles(UPSTREAM_HOLDER, BASE);
|
||||
const stillUpstream = grepFiles(UPSTREAM_HOLDER, ref);
|
||||
const left = [];
|
||||
let rewritten = 0;
|
||||
let shared = 0;
|
||||
for (const [path, [lines]] of baseFiles) {
|
||||
const n = lines - (changes.get(path)?.[1] ?? 0);
|
||||
if (n <= 0) continue;
|
||||
if (!headed.has(path) || stillUpstream.has(path)) left.push([n, path]);
|
||||
else {
|
||||
rewritten += 1;
|
||||
shared += n;
|
||||
}
|
||||
}
|
||||
left.sort((a, b) => b[0] - a[0] || a[1].localeCompare(b[1]));
|
||||
const upstreamLeft = left.reduce((n, [l]) => n + l, 0);
|
||||
const notUpstream = forkLines - upstreamLeft;
|
||||
const dual = grepFiles(DUAL_HEADER, ref).size;
|
||||
|
||||
const pct = (a, b) => `${((100 * a) / b).toFixed(1)}%`;
|
||||
const n = (x) => x.toLocaleString('en-US');
|
||||
console.log(`Against upstream v1.0.11 (${BASE.slice(0, 7)}), at ${git('rev-parse', '--short', ref).trim()}:`);
|
||||
console.log(` not upstream's: ${pct(notUpstream, forkLines)} (${n(notUpstream)} of ${n(forkLines)} lines)`);
|
||||
console.log(` upstream lines left: ${n(upstreamLeft)} of ${n(upstreamLines)}, in ${n(left.length)} files`);
|
||||
console.log(` dual-header files: ${n(dual)}`);
|
||||
console.log(` rewritten files: ${n(rewritten)}, sharing ${n(shared)} lines with upstream's`);
|
||||
if (showFiles) {
|
||||
console.log('');
|
||||
for (const [l, path] of left) console.log(`${String(l).padStart(6)} ${path}`);
|
||||
}
|
||||
Reference in new issue
Block a user