Skip to content

Commit 45064cf

Browse files
authored
Merge pull request #1125 from goldants/private-npm-repositories
Private npm repositories
2 parents 5558e7d + 7253e3d commit 45064cf

File tree

26 files changed

+947
-29
lines changed

26 files changed

+947
-29
lines changed

client/packages/lowcoder-cli/client.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ declare var PUBLIC_URL: string;
2929
declare var REACT_APP_EDITION: string;
3030
declare var REACT_APP_LANGUAGES: string;
3131
declare var REACT_APP_COMMIT_ID: string;
32-
declare var REACT_APP_API_HOST: string;
33-
declare var LOWCODER_NODE_SERVICE_URL: string;
32+
declare var REACT_APP_API_SERVICE_URL: string;
33+
declare var REACT_APP_NODE_SERVICE_URL: string;
3434
declare var REACT_APP_ENV: string;
3535
declare var REACT_APP_BUILD_ID: string;
3636
declare var REACT_APP_LOG_LEVEL: string;

client/packages/lowcoder-cli/dev-utils/buildVars.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ export const buildVars = [
1616
defaultValue: "00000",
1717
},
1818
{
19-
name: "REACT_APP_API_HOST",
19+
name: "REACT_APP_API_SERVICE_URL",
2020
defaultValue: "",
2121
},
2222
{
23-
name: "LOWCODER_NODE_SERVICE_URL",
23+
name: "REACT_APP_NODE_SERVICE_URL",
2424
defaultValue: "",
2525
},
2626
{

client/packages/lowcoder-sdk-webpack-bundle/src/dev-utils/buildVars.cjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ const buildVars = [
1616
defaultValue: "00000",
1717
},
1818
{
19-
name: "REACT_APP_API_HOST",
19+
name: "REACT_APP_API_SERVICE_URL",
2020
defaultValue: "",
2121
},
2222
{
23-
name: "LOWCODER_NODE_SERVICE_URL",
23+
name: "REACT_APP_NODE_SERVICE_URL",
2424
defaultValue: "",
2525
},
2626
{

client/packages/lowcoder-sdk-webpack-bundle/webpack.config.cjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ module.exports = {
102102
plugins: [
103103
new webpack.DefinePlugin({
104104
...define,
105-
REACT_APP_API_HOST: JSON.stringify(apiBaseUrl),
105+
REACT_APP_API_SERVICE_URL: JSON.stringify(apiBaseUrl),
106106
REACT_APP_BUNDLE_TYPE: JSON.stringify("sdk"),
107107
}),
108108
new webpack.IgnorePlugin({

client/packages/lowcoder-sdk/src/dev-utils/buildVars.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ export const buildVars = [
1616
defaultValue: "00000",
1717
},
1818
{
19-
name: "REACT_APP_API_HOST",
19+
name: "REACT_APP_API_SERVICE_URL",
2020
defaultValue: "",
2121
},
2222
{
23-
name: "LOWCODER_NODE_SERVICE_URL",
23+
name: "REACT_APP_NODE_SERVICE_URL",
2424
defaultValue: "",
2525
},
2626
{

client/packages/lowcoder-sdk/vite.config.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const apiBaseUrl = "http://localhost:8000";
2121
export const viteConfig: UserConfig = {
2222
define: {
2323
...define,
24-
REACT_APP_API_HOST: JSON.stringify(apiBaseUrl),
24+
REACT_APP_API_SERVICE_URL: JSON.stringify(apiBaseUrl),
2525
REACT_APP_BUNDLE_TYPE: JSON.stringify("sdk"),
2626
},
2727
assetsInclude: ["**/*.md"],

client/packages/lowcoder/src/app-env.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ declare var PUBLIC_URL: string;
3535
declare var REACT_APP_EDITION: string;
3636
declare var REACT_APP_LANGUAGES: string;
3737
declare var REACT_APP_COMMIT_ID: string;
38-
declare var REACT_APP_API_HOST: string;
39-
declare var LOWCODER_NODE_SERVICE_URL: string;
38+
declare var REACT_APP_API_SERVICE_URL: string;
39+
declare var REACT_APP_NODE_SERVICE_URL: string;
4040
declare var REACT_APP_ENV: string;
4141
declare var REACT_APP_BUILD_ID: string;
4242
declare var REACT_APP_LOG_LEVEL: string;
Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
import { useEffect, useState } from "react";
2+
import { HelpText } from "./HelpText";
3+
import { FormInputItem, FormSelectItem, TacoSwitch } from "lowcoder-design";
4+
import { Form } from "antd";
5+
import { trans } from "@lowcoder-ee/i18n";
6+
import { FormStyled } from "@lowcoder-ee/pages/setting/idSource/styledComponents";
7+
import { SaveButton } from "@lowcoder-ee/pages/setting/styled";
8+
import { NpmRegistryConfigEntry } from "@lowcoder-ee/redux/reducers/uiReducers/commonSettingsReducer";
9+
10+
type NpmRegistryConfigEntryInput = {
11+
url: string;
12+
scope: "global" | "organization" | "package";
13+
pattern: string;
14+
authType: "none" | "basic" | "bearer";
15+
credentials: string;
16+
};
17+
18+
const initialRegistryConfig: NpmRegistryConfigEntryInput = {
19+
scope: "global",
20+
pattern: "",
21+
url: "",
22+
authType: "none",
23+
credentials: "",
24+
};
25+
26+
interface NpmRegistryConfigProps {
27+
initialData?: NpmRegistryConfigEntry;
28+
onSave: (registryConfig: NpmRegistryConfigEntry|null) => void;
29+
}
30+
31+
export function NpmRegistryConfig(props: NpmRegistryConfigProps) {
32+
const [initialConfigSet, setItialConfigSet] = useState<boolean>(false);
33+
const [enableRegistry, setEnableRegistry] = useState<boolean>(!!props.initialData);
34+
const [registryConfig, setRegistryConfig] = useState<NpmRegistryConfigEntryInput>(initialRegistryConfig);
35+
36+
useEffect(() => {
37+
if (props.initialData && !initialConfigSet) {
38+
let initConfig: NpmRegistryConfigEntryInput = {...initialRegistryConfig};
39+
if (props.initialData) {
40+
const {scope} = props.initialData;
41+
const {type: scopeTye, pattern} = scope;
42+
const {url, auth} = props.initialData.registry;
43+
const {type: authType, credentials} = props.initialData.registry.auth;
44+
initConfig.scope = scopeTye;
45+
initConfig.pattern = pattern || "";
46+
initConfig.url = url;
47+
initConfig.authType = authType;
48+
initConfig.credentials = credentials || "";
49+
}
50+
51+
form.setFieldsValue(initConfig);
52+
setRegistryConfig(initConfig);
53+
setEnableRegistry(true);
54+
setItialConfigSet(true);
55+
}
56+
}, [props.initialData, initialConfigSet]);
57+
58+
useEffect(() => {
59+
if (!enableRegistry) {
60+
form.resetFields();
61+
setRegistryConfig(initialRegistryConfig);
62+
}
63+
}, [enableRegistry]);
64+
65+
const [form] = Form.useForm();
66+
67+
const handleRegistryConfigChange = async (key: string, value: string) => {
68+
let keyConfg = { [key]: value };
69+
form.validateFields([key]);
70+
71+
// Reset the pattern field if the scope is global
72+
if (key === "scope") {
73+
if (value !== "global") {
74+
registryConfig.scope !== "global" && form.validateFields(["pattern"]);
75+
} else {
76+
form.resetFields(["pattern"]);
77+
keyConfg = {
78+
...keyConfg,
79+
pattern: ""
80+
};
81+
}
82+
}
83+
84+
// Reset the credentials field if the auth type is none
85+
if (key === "authType") {
86+
if (value !== "none") {
87+
registryConfig.authType !== "none" && form.validateFields(["credentials"]);
88+
} else {
89+
form.resetFields(["credentials"]);
90+
keyConfg = {
91+
...keyConfg,
92+
credentials: ""
93+
};
94+
}
95+
}
96+
97+
// Update the registry config
98+
setRegistryConfig((prevConfig) => ({
99+
...prevConfig,
100+
...keyConfg,
101+
}));
102+
};
103+
104+
const scopeOptions = [
105+
{
106+
value: "global",
107+
label: "Global",
108+
},
109+
{
110+
value: "organization",
111+
label: "Organization",
112+
},
113+
{
114+
value: "package",
115+
label: "Package",
116+
},
117+
];
118+
119+
const authOptions = [
120+
{
121+
value: "none",
122+
label: "None",
123+
},
124+
{
125+
value: "basic",
126+
label: "Basic",
127+
},
128+
{
129+
value: "bearer",
130+
label: "Token",
131+
},
132+
];
133+
134+
const onFinsish = () => {
135+
const registryConfigEntry: NpmRegistryConfigEntry = {
136+
scope: {
137+
type: registryConfig.scope,
138+
pattern: registryConfig.pattern,
139+
},
140+
registry: {
141+
url: registryConfig.url,
142+
auth: {
143+
type: registryConfig.authType,
144+
credentials: registryConfig.credentials,
145+
},
146+
},
147+
};
148+
props.onSave(registryConfigEntry);
149+
}
150+
151+
return (
152+
<FormStyled
153+
form={form}
154+
name="basic"
155+
layout="vertical"
156+
style={{ maxWidth: 440 }}
157+
initialValues={initialRegistryConfig}
158+
autoComplete="off"
159+
onValuesChange={(changedValues, allValues) => {
160+
for (const key in changedValues) {
161+
handleRegistryConfigChange(key, changedValues[key]);
162+
}
163+
}}
164+
onFinish={onFinsish}
165+
>
166+
<div style={{ paddingBottom: "10px"}}>
167+
<TacoSwitch checked={enableRegistry} label={trans("npmRegistry.npmRegistryEnable")} onChange={function (checked: boolean): void {
168+
setEnableRegistry(checked);
169+
if (!checked) {
170+
form.resetFields();
171+
}
172+
} }></TacoSwitch>
173+
</div>
174+
<div hidden={!enableRegistry}>
175+
<div className="ant-form-item-label" style={{ paddingBottom: "10px" }}>
176+
<label>Registry</label>
177+
</div>
178+
<FormInputItem
179+
name={"url"}
180+
placeholder={trans("npmRegistry.npmRegistryUrl")}
181+
style={{ width: "544px", height: "32px", marginBottom: 12 }}
182+
value={registryConfig.url}
183+
rules={[{
184+
required: true,
185+
message: trans("npmRegistry.npmRegistryUrlRequired"),
186+
},
187+
{
188+
type: "url",
189+
message: trans("npmRegistry.npmRegistryUrlInvalid"),
190+
}
191+
]}
192+
/>
193+
<div className="ant-form-item-label" style={{ paddingBottom: "10px" }}>
194+
<label>Scope</label>
195+
</div>
196+
<div
197+
style={{ display: "flex", alignItems: "baseline", maxWidth: "560px" }}
198+
>
199+
<div style={{ flex: 1, paddingRight: "8px" }}>
200+
<FormSelectItem
201+
name={"scope"}
202+
placeholder={trans("npmRegistry.npmRegistryScope")}
203+
style={{ width: "264px", height: "32px", marginBottom: 12 }}
204+
initialValue={registryConfig.scope}
205+
options={scopeOptions}
206+
/>
207+
</div>
208+
<div style={{ flex: 1, paddingRight: "8px" }}>
209+
<FormInputItem
210+
name={"pattern"}
211+
placeholder={trans("npmRegistry.npmRegistryPattern")}
212+
style={{ width: "264px", height: "32px", marginBottom: 12 }}
213+
hidden={
214+
registryConfig.scope !== "organization" &&
215+
registryConfig.scope !== "package"
216+
}
217+
value={registryConfig.pattern}
218+
rules={[{
219+
required: registryConfig.scope === "organization" || registryConfig.scope === "package",
220+
message: "Please input the package scope pattern",
221+
},
222+
{
223+
message: trans("npmRegistry.npmRegistryPatternInvalid"),
224+
validator: async (_, value) => {
225+
if (registryConfig.scope === "global") {
226+
return;
227+
}
228+
229+
if (registryConfig.scope === "organization") {
230+
if(!/^\@[a-zA-Z0-9-_.]+$/.test(value)) {
231+
throw new Error("Input pattern not starting with @");
232+
}
233+
} else {
234+
if(!/^[a-zA-Z0-9-_.]+$/.test(value)) {
235+
throw new Error("Input pattern not valid");
236+
}
237+
}
238+
}
239+
}
240+
]}
241+
/>
242+
</div>
243+
</div>
244+
<div className="ant-form-item-label" style={{ padding: "10px 0" }}>
245+
<label>{trans("npmRegistry.npmRegistryAuth")}</label>
246+
</div>
247+
<HelpText style={{ marginBottom: 12 }} hidden={registryConfig.authType === "none"}>
248+
{trans("npmRegistry.npmRegistryAuthCredentialsHelp")}
249+
</HelpText>
250+
<div style={{ display: "flex", alignItems: "baseline", maxWidth: "560px" }}>
251+
<div style={{ flex: 1, paddingRight: "8px" }}>
252+
<FormSelectItem
253+
name={"authType"}
254+
placeholder={trans("npmRegistry.npmRegistryAuthType")}
255+
style={{ width: "264px", height: "32px", marginBottom: 12 }}
256+
initialValue={registryConfig.authType}
257+
options={authOptions}
258+
/>
259+
</div>
260+
<div style={{ flex: 1, paddingRight: "8px" }}>
261+
<Form.Item rules={[{required: true}]}>
262+
<FormInputItem
263+
name={"credentials"}
264+
placeholder={trans("npmRegistry.npmRegistryAuthCredentials")}
265+
style={{ width: "264px", height: "32px", marginBottom: 12 }}
266+
hidden={registryConfig.authType === "none"}
267+
value={registryConfig.credentials}
268+
rules={[{
269+
message: trans("npmRegistry.npmRegistryAuthCredentialsRequired"),
270+
validator: async (_, value) => {
271+
if (registryConfig.authType === "none") {
272+
return;
273+
}
274+
if (!value) {
275+
throw new Error("No credentials provided");
276+
}
277+
}
278+
}]}
279+
/>
280+
</Form.Item>
281+
</div>
282+
</div>
283+
</div>
284+
<Form.Item>
285+
<SaveButton
286+
buttonType="primary"
287+
htmlType="submit"
288+
onClick={() => {
289+
if (!enableRegistry) {
290+
return props.onSave(null);
291+
}
292+
}
293+
}>
294+
{trans("advanced.saveBtn")}
295+
</SaveButton>
296+
</Form.Item>
297+
</FormStyled>
298+
);
299+
}

0 commit comments

Comments
 (0)