Skip to content

Commit 7ac1f9b

Browse files
authored
Feat/bindings (#10)
* new bindings * feat: integrate bindings into manage context and update binding logic - Added bindings to the ManageContext to manage package bindings. - Updated BindPackage component to utilize bindings for rollout configuration. - Modified types to include packageId in the Binding interface. - Refactored useBindings hook to streamline binding retrieval. * fix sider * deps * migrate to bindings * fix binding * update dependencies and fix type references - Bump @rsbuild/core to version 1.6.1 and @biomejs/biome to version 2.3.3 in package.json and bun.lock. - Change type definition from 'version' to 'versions' in Package interface for better clarity. - Update BindPackage component to reference 'versions' for package version checks. - Modify request service to use localhost for development. * update * improve error msg * Update BindPackage component labels for clarity - Changed label from "取消绑定" to "取消发布" for unpublish action. - Updated button text from "绑定" to "发布" to reflect the new context.
1 parent 3b599f5 commit 7ac1f9b

File tree

14 files changed

+475
-305
lines changed

14 files changed

+475
-305
lines changed

bun.lock

Lines changed: 86 additions & 96 deletions
Large diffs are not rendered by default.

package.json

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,32 +8,32 @@
88
"lint": "tsc --noEmit & biome check --write ."
99
},
1010
"dependencies": {
11-
"@ant-design/icons": "^6.0.2",
11+
"@ant-design/icons": "^6.1.0",
1212
"@ant-design/v5-patch-for-react-19": "^1.0.3",
13-
"@rsbuild/core": "^1.5.13",
13+
"@rsbuild/core": "^1.6.1",
1414
"@rsbuild/plugin-react": "^1.4.1",
1515
"@rsbuild/plugin-sass": "^1.4.0",
1616
"@rsbuild/plugin-svgr": "^1.2.2",
17-
"@tanstack/react-query": "^5.90.2",
18-
"antd": "^5.27.4",
19-
"dayjs": "^1.11.18",
17+
"@tanstack/react-query": "^5.90.6",
18+
"antd": "^5.28.0",
19+
"dayjs": "^1.11.19",
2020
"git-url-parse": "^16.1.0",
2121
"hash-wasm": "^4.12.0",
2222
"history": "^5.3.0",
2323
"json-diff-kit": "^1.0.33",
24-
"react": "^19.1.1",
25-
"react-dom": "^19.1.1",
26-
"react-router-dom": "^7.9.3",
24+
"react": "^19.2.0",
25+
"react-dom": "^19.2.0",
26+
"react-router-dom": "^7.9.5",
2727
"vanilla-jsoneditor": "^3.10.0"
2828
},
2929
"devDependencies": {
30-
"@biomejs/biome": "2.2.4",
31-
"@tailwindcss/postcss": "^4.1.13",
30+
"@biomejs/biome": "2.3.3",
31+
"@tailwindcss/postcss": "^4.1.16",
3232
"@types/git-url-parse": "^16.0.2",
3333
"@types/react": "^19",
3434
"@types/react-dom": "^19",
3535
"@types/react-router-dom": "^5.3.3",
36-
"tailwindcss": "^4.1.13",
36+
"tailwindcss": "^4.1.16",
3737
"typescript": "^5.9.3"
3838
},
3939
"trustedDependencies": [

src/components/error-boundary.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@ export function ErrorBoundary() {
1010
const error = useRouteError() as ChunkError;
1111
const navigate = useNavigate();
1212

13+
const message = error?.message || "";
14+
1315
const isChunkError =
14-
error?.message?.includes("Loading CSS chunk") ||
15-
error?.message?.includes("Loading chunk") ||
16-
error?.message?.includes("ChunkLoadError");
16+
message &&
17+
(message.includes("Loading CSS chunk") ||
18+
message.includes("Loading chunk") ||
19+
message.includes("ChunkLoadError"));
1720

1821
useEffect(() => {
1922
if (isChunkError) {
@@ -33,7 +36,7 @@ export function ErrorBoundary() {
3336
<Result
3437
status="500"
3538
title="页面出错了"
36-
subTitle={error?.message || "发生了未知错误"}
39+
subTitle={message || "发生了未知错误"}
3740
extra={
3841
<>
3942
<Button type="primary" onClick={handleRetry}>

src/pages/manage/components/bind-package.tsx

Lines changed: 106 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -7,109 +7,128 @@ import {
77
} from "@ant-design/icons";
88
import { Button, Dropdown, type MenuProps } from "antd";
99
import { useManageContext } from "../hooks/useManageContext";
10+
import { useMemo } from "react";
1011

1112
const BindPackage = ({
12-
packages,
1313
versionId,
1414
config,
1515
}: {
16-
packages: PackageBase[];
1716
versionId: number;
1817
config: Version["config"];
1918
}) => {
20-
const { packages: allPackages, appId } = useManageContext();
21-
const availablePackages = allPackages.filter(
22-
(i) => !packages.some((j) => i.id === j.id),
23-
);
19+
const {
20+
packages: allPackages,
21+
appId,
22+
bindings,
23+
packageMap,
24+
} = useManageContext();
25+
const availablePackages = allPackages;
26+
27+
const bindedPackages = useMemo(() => {
28+
const result = [];
29+
const legacyBindings = [];
30+
for (const p of allPackages) {
31+
if (p.versions?.id === versionId) {
32+
const legacyConfig = config?.rollout?.[p.name];
33+
legacyBindings.push({
34+
packageId: p.id,
35+
rollout: legacyConfig,
36+
});
37+
continue;
38+
}
39+
}
40+
const matchedBindings: {
41+
id?: number;
42+
packageId: number;
43+
rollout: number | null | undefined;
44+
}[] = legacyBindings.concat(
45+
bindings.filter((b) => b.versionId === versionId)
46+
);
47+
48+
if (matchedBindings.length === 0 || allPackages.length === 0) return null;
2449

25-
const bindedPackages = packages.map((p) => {
26-
const rolloutConfig = config?.rollout?.[p.name];
27-
const isFull =
28-
rolloutConfig === 100 ||
29-
rolloutConfig === undefined ||
30-
rolloutConfig === null;
31-
const rolloutConfigNumber = Number(rolloutConfig);
32-
const menu: MenuProps = {
33-
items: isFull
50+
for (const binding of matchedBindings) {
51+
const p = packageMap.get(binding.packageId)!;
52+
const rolloutConfig = binding.rollout;
53+
const isFull =
54+
rolloutConfig === 100 ||
55+
rolloutConfig === undefined ||
56+
rolloutConfig === null;
57+
const rolloutConfigNumber = Number(rolloutConfig);
58+
const items: MenuProps["items"] = isFull
3459
? []
3560
: [
3661
{
3762
key: "full",
3863
label: "全量",
3964
icon: <CloudDownloadOutlined />,
40-
onClick: () => {
41-
api.updateVersion({
65+
onClick: () =>
66+
api.upsertBinding({
4267
appId,
68+
packageId: binding.packageId,
4369
versionId,
44-
params: { config: { rollout: { [p.name]: null } } },
45-
});
46-
api.updatePackage({
47-
appId,
48-
packageId: p.id,
49-
params: { versionId },
50-
});
51-
},
70+
}),
5271
},
53-
],
54-
};
72+
];
5573

56-
if (rolloutConfigNumber < 50 && !isFull) {
57-
menu.items!.push({
58-
key: "gray",
59-
label: "灰度",
60-
icon: <ExperimentOutlined />,
61-
onClick: () =>
62-
api.updatePackage({ appId, packageId: p.id, params: { versionId } }),
63-
children: [1, 2, 5, 10, 20, 50]
64-
.filter((percentage) => percentage > rolloutConfigNumber)
65-
.map((percentage) => ({
66-
key: `${percentage}`,
67-
label: `${percentage}%`,
68-
onClick: () =>
69-
api.updateVersion({
70-
appId,
71-
versionId,
72-
params: { config: { rollout: { [p.name]: percentage } } },
73-
}),
74-
})),
74+
if (rolloutConfigNumber < 50 && !isFull) {
75+
items.push({
76+
key: "gray",
77+
label: "灰度",
78+
icon: <ExperimentOutlined />,
79+
children: [1, 2, 5, 10, 20, 50]
80+
.filter((percentage) => percentage > rolloutConfigNumber)
81+
.map((percentage) => ({
82+
key: `${percentage}`,
83+
label: `${percentage}%`,
84+
onClick: () =>
85+
api.upsertBinding({
86+
appId,
87+
packageId: binding.packageId,
88+
versionId,
89+
rollout: percentage,
90+
}),
91+
})),
92+
});
93+
}
94+
if (items.length > 0) {
95+
items.push({ type: "divider" });
96+
}
97+
items.push({
98+
key: "unpublish",
99+
label: "取消发布",
100+
icon: <RestOutlined />,
101+
onClick: () => {
102+
const bindingId = binding.id;
103+
if (bindingId) {
104+
api.deleteBinding({ appId, bindingId });
105+
} else {
106+
api.updatePackage({
107+
appId,
108+
packageId: p.id,
109+
params: { versionId: null },
110+
});
111+
}
112+
},
75113
});
114+
const button = (
115+
<Button
116+
size="small"
117+
color="primary"
118+
variant={isFull ? "filled" : "dashed"}
119+
>
120+
<span className="font-bold">{p.name}</span>
121+
<span className="text-xs">{isFull ? "" : `(${rolloutConfig}%)`}</span>
122+
</Button>
123+
);
124+
result.push(
125+
<Dropdown key={p.id} menu={{ items }}>
126+
{button}
127+
</Dropdown>
128+
);
76129
}
77-
if (menu.items!.length > 0) {
78-
menu.items!.push({ type: "divider" });
79-
}
80-
menu.items!.push({
81-
key: "unpublish",
82-
label: "取消绑定",
83-
icon: <RestOutlined />,
84-
onClick: () => {
85-
api.updateVersion({
86-
appId,
87-
versionId,
88-
params: { config: { rollout: { [p.name]: null } } },
89-
});
90-
api.updatePackage({
91-
appId,
92-
packageId: p.id,
93-
params: { versionId: null },
94-
});
95-
},
96-
});
97-
const button = (
98-
<Button
99-
size="small"
100-
color="primary"
101-
variant={isFull ? "filled" : "dashed"}
102-
>
103-
<span className="font-bold">{p.name}</span>
104-
<span className="text-xs">{isFull ? "" : `(${rolloutConfig}%)`}</span>
105-
</Button>
106-
);
107-
return (
108-
<Dropdown key={p.id} menu={menu}>
109-
{button}
110-
</Dropdown>
111-
);
112-
});
130+
return result;
131+
}, [allPackages, bindings, versionId]);
113132

114133
return (
115134
<div className="flex flex-wrap gap-1">
@@ -120,23 +139,13 @@ const BindPackage = ({
120139
items: availablePackages.map((p) => ({
121140
key: p.id,
122141
label: p.name,
123-
onClick: () =>
124-
api.updatePackage({
125-
appId,
126-
packageId: p.id,
127-
params: { versionId },
128-
}),
129142
children: [
130143
{
131144
key: "full",
132145
label: "全量",
133146
icon: <CloudDownloadOutlined />,
134147
onClick: () =>
135-
api.updateVersion({
136-
appId,
137-
versionId,
138-
params: { config: { rollout: { [p.name]: null } } },
139-
}),
148+
api.upsertBinding({ appId, packageId: p.id, versionId }),
140149
},
141150
{
142151
key: "gray",
@@ -146,12 +155,11 @@ const BindPackage = ({
146155
key: `${percentage}`,
147156
label: `${percentage}%`,
148157
onClick: () =>
149-
api.updateVersion({
158+
api.upsertBinding({
150159
appId,
160+
packageId: p.id,
151161
versionId,
152-
params: {
153-
config: { rollout: { [p.name]: percentage } },
154-
},
162+
rollout: percentage,
155163
}),
156164
})),
157165
},
@@ -161,7 +169,7 @@ const BindPackage = ({
161169
className="ant-typography-edit"
162170
>
163171
<Button type="link" size="small" icon={<LinkOutlined />}>
164-
绑定
172+
发布
165173
</Button>
166174
</Dropdown>
167175
)}

src/pages/manage/components/package-list.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ const Item = ({ item }: { item: Package }) => {
8686
const { appId } = useManageContext();
8787
return (
8888
// const [_, drag] = useDrag(() => ({ item, type: "package" }));
89-
<div className="bg-white my-0 [&_li]:!px-0">
89+
<div className="bg-white my-0 [&_li]:px-0!">
9090
<List.Item className="p-2">
9191
<List.Item.Meta
9292
title={

0 commit comments

Comments
 (0)