nsgm-cli 2.1.20 → 2.1.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -0
- package/client/components/Button.tsx +2 -4
- package/client/components/ClientProviders.tsx +12 -12
- package/client/components/LanguageSwitcher.tsx +26 -26
- package/client/components/SSRSafeAntdProvider.tsx +7 -7
- package/client/components/SuppressHydrationWarnings.tsx +30 -30
- package/client/components/__tests__/Button.test.tsx +12 -12
- package/client/layout/index.tsx +122 -124
- package/client/redux/reducers.ts +2 -2
- package/client/redux/store.ts +24 -24
- package/client/redux/template/manage/actions.ts +40 -40
- package/client/redux/template/manage/reducers.ts +32 -32
- package/client/redux/template/manage/types.ts +19 -19
- package/client/service/template/manage.ts +29 -29
- package/client/styled/common.ts +6 -6
- package/client/styled/layout/index.ts +17 -17
- package/client/styled/template/manage.ts +19 -19
- package/client/utils/common.ts +52 -54
- package/client/utils/cookie.ts +30 -30
- package/client/utils/fetch.ts +111 -111
- package/client/utils/i18n.ts +41 -41
- package/client/utils/menu.tsx +11 -12
- package/client/utils/navigation.ts +22 -22
- package/client/utils/sso.ts +124 -124
- package/client/utils/suppressWarnings.ts +17 -17
- package/generation/client/utils/menu.tsx +0 -1
- package/jest.config.js +4 -4
- package/lib/args.js +19 -19
- package/lib/cli/app.d.ts +1 -1
- package/lib/cli/app.js +2 -2
- package/lib/cli/commands/build.d.ts +1 -1
- package/lib/cli/commands/build.js +9 -9
- package/lib/cli/commands/create.d.ts +1 -1
- package/lib/cli/commands/create.js +36 -36
- package/lib/cli/commands/delete.d.ts +1 -1
- package/lib/cli/commands/delete.js +55 -55
- package/lib/cli/commands/export.d.ts +1 -1
- package/lib/cli/commands/export.js +12 -12
- package/lib/cli/commands/help.d.ts +1 -1
- package/lib/cli/commands/help.js +29 -29
- package/lib/cli/commands/init.d.ts +1 -1
- package/lib/cli/commands/init.js +31 -31
- package/lib/cli/commands/server.d.ts +1 -1
- package/lib/cli/commands/server.js +12 -12
- package/lib/cli/commands/upgrade.d.ts +1 -1
- package/lib/cli/commands/upgrade.js +13 -13
- package/lib/cli/commands/version.d.ts +1 -1
- package/lib/cli/commands/version.js +7 -7
- package/lib/cli/index.d.ts +13 -13
- package/lib/cli/parser.d.ts +1 -1
- package/lib/cli/parser.js +12 -12
- package/lib/cli/registry.d.ts +1 -1
- package/lib/cli/types.d.ts +2 -2
- package/lib/cli/utils/console.d.ts +2 -2
- package/lib/cli/utils/console.js +22 -22
- package/lib/cli/utils/index.d.ts +2 -2
- package/lib/cli/utils/prompt.d.ts +1 -1
- package/lib/cli/utils/prompt.js +98 -98
- package/lib/constants.js +28 -28
- package/lib/generate.d.ts +2 -2
- package/lib/generate.js +19 -19
- package/lib/generate_create.d.ts +1 -1
- package/lib/generate_create.js +38 -38
- package/lib/generate_delete.js +63 -63
- package/lib/generate_init.js +93 -93
- package/lib/generators/base-generator.d.ts +1 -1
- package/lib/generators/base-generator.js +23 -23
- package/lib/generators/file-generator.js +15 -15
- package/lib/generators/generator-factory.d.ts +5 -5
- package/lib/generators/i18n-generator.d.ts +1 -1
- package/lib/generators/i18n-generator.js +127 -127
- package/lib/generators/page-generator.d.ts +1 -1
- package/lib/generators/page-generator.js +25 -25
- package/lib/generators/resolver-generator.d.ts +1 -1
- package/lib/generators/resolver-generator.js +27 -27
- package/lib/generators/schema-generator.d.ts +1 -1
- package/lib/generators/schema-generator.js +4 -4
- package/lib/generators/service-generator.d.ts +1 -1
- package/lib/generators/service-generator.js +29 -29
- package/lib/generators/sql-generator.d.ts +1 -1
- package/lib/generators/sql-generator.js +10 -10
- package/lib/index.js +33 -30
- package/lib/server/csrf.d.ts +3 -3
- package/lib/server/csrf.js +20 -20
- package/lib/server/db.d.ts +1 -1
- package/lib/server/db.js +21 -21
- package/lib/server/graphql.js +26 -26
- package/lib/server/plugins/date.d.ts +1 -1
- package/lib/server/plugins/date.js +6 -6
- package/lib/server/utils/graphql-cache.js +5 -5
- package/lib/tsconfig.build.tsbuildinfo +1 -1
- package/lib/utils/project-config.d.ts +1 -1
- package/lib/utils/project-config.js +20 -20
- package/lib/utils.js +3 -3
- package/next-env.d.ts +1 -0
- package/next.config.js +15 -109
- package/package.json +5 -3
- package/pages/_app.tsx +62 -65
- package/pages/_document.tsx +14 -15
- package/pages/_error.tsx +25 -26
- package/pages/index.tsx +47 -48
- package/pages/login.tsx +64 -64
- package/pages/template/manage.tsx +175 -175
package/README.md
CHANGED
|
@@ -383,6 +383,8 @@ npm run export
|
|
|
383
383
|
|
|
384
384
|
### Production Deployment
|
|
385
385
|
|
|
386
|
+
#### Local Deployment
|
|
387
|
+
|
|
386
388
|
```bash
|
|
387
389
|
# Start production server
|
|
388
390
|
npm start
|
|
@@ -391,6 +393,44 @@ npm start
|
|
|
391
393
|
pm2 start npm --name "nsgm-app" -- start
|
|
392
394
|
```
|
|
393
395
|
|
|
396
|
+
#### Vercel Deployment (Recommended)
|
|
397
|
+
|
|
398
|
+
NSGM CLI 完全支持 Vercel 部署,包括自动化 CI/CD 流程。
|
|
399
|
+
|
|
400
|
+
**快速开始:**
|
|
401
|
+
|
|
402
|
+
1. 推送项目到 GitHub
|
|
403
|
+
2. 访问 [Vercel Dashboard](https://vercel.com/dashboard)
|
|
404
|
+
3. 导入 GitHub 仓库
|
|
405
|
+
4. 配置环境变量(参考 `.env.vercel.example`)
|
|
406
|
+
5. 点击 "Deploy"
|
|
407
|
+
|
|
408
|
+
**详细指南:** 查看 [VERCEL_DEPLOYMENT.md](VERCEL_DEPLOYMENT.md)
|
|
409
|
+
|
|
410
|
+
**特性:**
|
|
411
|
+
|
|
412
|
+
- ✅ 自动 CI/CD 流程
|
|
413
|
+
- ✅ 预览环境(每个 PR)
|
|
414
|
+
- ✅ 自动 HTTPS
|
|
415
|
+
- ✅ 全球 CDN
|
|
416
|
+
- ✅ 无服务器函数
|
|
417
|
+
- ✅ 一键回滚
|
|
418
|
+
|
|
419
|
+
**环境变量配置:**
|
|
420
|
+
|
|
421
|
+
```
|
|
422
|
+
NODE_ENV=production
|
|
423
|
+
LOGIN_USERNAME=admin
|
|
424
|
+
LOGIN_PASSWORD_HASH=your_hash
|
|
425
|
+
DATABASE_URL=mysql://...
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
**获取密码哈希:**
|
|
429
|
+
|
|
430
|
+
```bash
|
|
431
|
+
npm run generate-password yourPassword
|
|
432
|
+
```
|
|
433
|
+
|
|
394
434
|
## 🤝 Contributing
|
|
395
435
|
|
|
396
436
|
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
// src/components/Button.js
|
|
2
|
-
|
|
2
|
+
const Button = ({ onClick, children }) => <button onClick={onClick}>{children}</button>;
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export default Button
|
|
4
|
+
export default Button;
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import React, { useEffect, useState } from
|
|
2
|
-
import { ThemeProvider } from
|
|
3
|
-
import { GlobalStyle } from
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import { ThemeProvider } from "styled-components";
|
|
3
|
+
import { GlobalStyle } from "@/styled/common";
|
|
4
4
|
|
|
5
5
|
interface ClientProvidersProps {
|
|
6
|
-
children: React.ReactNode
|
|
7
|
-
theme: any
|
|
8
|
-
whiteColor?: boolean
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
theme: any;
|
|
8
|
+
whiteColor?: boolean;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
const ClientProviders: React.FC<ClientProvidersProps> = ({ children, theme, whiteColor = true }) => {
|
|
12
|
-
const [isClient, setIsClient] = useState(false)
|
|
12
|
+
const [isClient, setIsClient] = useState(false);
|
|
13
13
|
|
|
14
14
|
useEffect(() => {
|
|
15
15
|
// 使用更安全的客户端检测
|
|
16
|
-
setIsClient(true)
|
|
17
|
-
}, [])
|
|
16
|
+
setIsClient(true);
|
|
17
|
+
}, []);
|
|
18
18
|
|
|
19
19
|
// 在服务端渲染时,使用一个占位符来保持结构一致性
|
|
20
20
|
// 但不渲染可能引起 useLayoutEffect 警告的组件
|
|
@@ -23,7 +23,7 @@ const ClientProviders: React.FC<ClientProvidersProps> = ({ children, theme, whit
|
|
|
23
23
|
{isClient && <GlobalStyle whiteColor={whiteColor} />}
|
|
24
24
|
{children}
|
|
25
25
|
</ThemeProvider>
|
|
26
|
-
)
|
|
27
|
-
}
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
28
|
|
|
29
|
-
export default ClientProviders
|
|
29
|
+
export default ClientProviders;
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
import React, { useEffect, useState } from
|
|
2
|
-
import { Select } from
|
|
3
|
-
import { useRouter } from
|
|
4
|
-
import { GlobalOutlined } from
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import { Select } from "antd";
|
|
3
|
+
import { useRouter } from "next/router";
|
|
4
|
+
import { GlobalOutlined } from "@ant-design/icons";
|
|
5
5
|
|
|
6
|
-
const { Option } = Select
|
|
6
|
+
const { Option } = Select;
|
|
7
7
|
|
|
8
8
|
interface LanguageSwitcherProps {
|
|
9
|
-
style?: React.CSSProperties
|
|
10
|
-
size?:
|
|
9
|
+
style?: React.CSSProperties;
|
|
10
|
+
size?: "small" | "middle" | "large";
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
const LanguageSwitcher: React.FC<LanguageSwitcherProps> = ({ style, size =
|
|
14
|
-
const router = useRouter()
|
|
15
|
-
const [mounted, setMounted] = useState(false)
|
|
16
|
-
const [currentLocale, setCurrentLocale] = useState(
|
|
13
|
+
const LanguageSwitcher: React.FC<LanguageSwitcherProps> = ({ style, size = "middle" }) => {
|
|
14
|
+
const router = useRouter();
|
|
15
|
+
const [mounted, setMounted] = useState(false);
|
|
16
|
+
const [currentLocale, setCurrentLocale] = useState("zh-CN");
|
|
17
17
|
|
|
18
18
|
useEffect(() => {
|
|
19
|
-
setMounted(true)
|
|
19
|
+
setMounted(true);
|
|
20
20
|
// 只在客户端获取当前语言
|
|
21
|
-
if (typeof window !==
|
|
22
|
-
setCurrentLocale(router.locale)
|
|
21
|
+
if (typeof window !== "undefined" && router.locale) {
|
|
22
|
+
setCurrentLocale(router.locale);
|
|
23
23
|
}
|
|
24
|
-
}, [router.locale])
|
|
24
|
+
}, [router.locale]);
|
|
25
25
|
|
|
26
26
|
const languages = [
|
|
27
|
-
{ code:
|
|
28
|
-
{ code:
|
|
29
|
-
{ code:
|
|
30
|
-
]
|
|
27
|
+
{ code: "zh-CN", name: "中文", flag: "🇨🇳" },
|
|
28
|
+
{ code: "en-US", name: "English", flag: "🇺🇸" },
|
|
29
|
+
{ code: "ja-JP", name: "日本語", flag: "🇯🇵" },
|
|
30
|
+
];
|
|
31
31
|
|
|
32
32
|
const handleLanguageChange = (locale: string) => {
|
|
33
|
-
if (mounted && typeof window !==
|
|
34
|
-
const { pathname, asPath, query } = router
|
|
35
|
-
router.push({ pathname, query }, asPath, { locale })
|
|
33
|
+
if (mounted && typeof window !== "undefined") {
|
|
34
|
+
const { pathname, asPath, query } = router;
|
|
35
|
+
router.push({ pathname, query }, asPath, { locale });
|
|
36
36
|
}
|
|
37
|
-
}
|
|
37
|
+
};
|
|
38
38
|
|
|
39
39
|
return (
|
|
40
40
|
<Select
|
|
@@ -53,7 +53,7 @@ const LanguageSwitcher: React.FC<LanguageSwitcherProps> = ({ style, size = 'midd
|
|
|
53
53
|
</Option>
|
|
54
54
|
))}
|
|
55
55
|
</Select>
|
|
56
|
-
)
|
|
57
|
-
}
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
58
|
|
|
59
|
-
export default LanguageSwitcher
|
|
59
|
+
export default LanguageSwitcher;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import { ConfigProvider } from
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ConfigProvider } from "antd";
|
|
3
3
|
|
|
4
4
|
interface SSRSafeAntdProviderProps {
|
|
5
|
-
children: React.ReactNode
|
|
6
|
-
locale?: any
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
locale?: any;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
const SSRSafeAntdProvider: React.FC<SSRSafeAntdProviderProps> = ({ children, locale }) => {
|
|
@@ -18,7 +18,7 @@ const SSRSafeAntdProvider: React.FC<SSRSafeAntdProviderProps> = ({ children, loc
|
|
|
18
18
|
>
|
|
19
19
|
{children}
|
|
20
20
|
</ConfigProvider>
|
|
21
|
-
)
|
|
22
|
-
}
|
|
21
|
+
);
|
|
22
|
+
};
|
|
23
23
|
|
|
24
|
-
export default SSRSafeAntdProvider
|
|
24
|
+
export default SSRSafeAntdProvider;
|
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
import { useEffect } from
|
|
1
|
+
import { useEffect } from "react";
|
|
2
2
|
|
|
3
3
|
// 全局抑制 useLayoutEffect 警告的函数
|
|
4
4
|
const suppressUseLayoutEffectWarnings = () => {
|
|
5
|
-
if (typeof window ===
|
|
6
|
-
const originalError = console.error
|
|
7
|
-
const originalWarn = console.warn
|
|
5
|
+
if (typeof window === "undefined" && process.env.NODE_ENV === "development") {
|
|
6
|
+
const originalError = console.error;
|
|
7
|
+
const originalWarn = console.warn;
|
|
8
8
|
|
|
9
9
|
console.error = (...args) => {
|
|
10
|
-
const errorMessage = args[0]
|
|
10
|
+
const errorMessage = args[0];
|
|
11
11
|
if (
|
|
12
|
-
typeof errorMessage ===
|
|
13
|
-
(errorMessage.includes(
|
|
14
|
-
errorMessage.includes(
|
|
12
|
+
typeof errorMessage === "string" &&
|
|
13
|
+
(errorMessage.includes("useLayoutEffect does nothing on the server") ||
|
|
14
|
+
errorMessage.includes("Warning: useLayoutEffect does nothing on the server"))
|
|
15
15
|
) {
|
|
16
|
-
return
|
|
16
|
+
return;
|
|
17
17
|
}
|
|
18
|
-
originalError.apply(console, args)
|
|
19
|
-
}
|
|
18
|
+
originalError.apply(console, args);
|
|
19
|
+
};
|
|
20
20
|
|
|
21
21
|
console.warn = (...args) => {
|
|
22
|
-
const warnMessage = args[0]
|
|
22
|
+
const warnMessage = args[0];
|
|
23
23
|
if (
|
|
24
|
-
typeof warnMessage ===
|
|
25
|
-
(warnMessage.includes(
|
|
26
|
-
warnMessage.includes(
|
|
24
|
+
typeof warnMessage === "string" &&
|
|
25
|
+
(warnMessage.includes("useLayoutEffect does nothing on the server") ||
|
|
26
|
+
warnMessage.includes("Warning: useLayoutEffect does nothing on the server"))
|
|
27
27
|
) {
|
|
28
|
-
return
|
|
28
|
+
return;
|
|
29
29
|
}
|
|
30
|
-
originalWarn.apply(console, args)
|
|
31
|
-
}
|
|
30
|
+
originalWarn.apply(console, args);
|
|
31
|
+
};
|
|
32
32
|
|
|
33
33
|
// 返回清理函数
|
|
34
34
|
return () => {
|
|
35
|
-
console.error = originalError
|
|
36
|
-
console.warn = originalWarn
|
|
37
|
-
}
|
|
35
|
+
console.error = originalError;
|
|
36
|
+
console.warn = originalWarn;
|
|
37
|
+
};
|
|
38
38
|
}
|
|
39
|
-
return undefined
|
|
40
|
-
}
|
|
39
|
+
return undefined;
|
|
40
|
+
};
|
|
41
41
|
|
|
42
42
|
// 在模块加载时立即执行
|
|
43
|
-
suppressUseLayoutEffectWarnings()
|
|
43
|
+
suppressUseLayoutEffectWarnings();
|
|
44
44
|
|
|
45
45
|
const SuppressHydrationWarnings = () => {
|
|
46
46
|
useEffect(() => {
|
|
47
47
|
// 在客户端也抑制这些警告(以防万一)
|
|
48
|
-
const cleanup = suppressUseLayoutEffectWarnings()
|
|
49
|
-
return cleanup
|
|
50
|
-
}, [])
|
|
48
|
+
const cleanup = suppressUseLayoutEffectWarnings();
|
|
49
|
+
return cleanup;
|
|
50
|
+
}, []);
|
|
51
51
|
|
|
52
|
-
return null
|
|
53
|
-
}
|
|
52
|
+
return null;
|
|
53
|
+
};
|
|
54
54
|
|
|
55
|
-
export default SuppressHydrationWarnings
|
|
55
|
+
export default SuppressHydrationWarnings;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
// src/components/Button.test.js
|
|
2
|
-
import { render, screen, fireEvent } from
|
|
3
|
-
import Button from
|
|
2
|
+
import { render, screen, fireEvent } from "@testing-library/react";
|
|
3
|
+
import Button from "../Button";
|
|
4
4
|
|
|
5
|
-
test(
|
|
6
|
-
render(<Button>Click me</Button>)
|
|
7
|
-
expect(screen.getByText(
|
|
8
|
-
})
|
|
5
|
+
test("renders button with text", () => {
|
|
6
|
+
render(<Button>Click me</Button>);
|
|
7
|
+
expect(screen.getByText("Click me")).toBeInTheDocument();
|
|
8
|
+
});
|
|
9
9
|
|
|
10
|
-
test(
|
|
11
|
-
const handleClick = jest.fn()
|
|
12
|
-
render(<Button onClick={handleClick}>Click me</Button>)
|
|
13
|
-
fireEvent.click(screen.getByText(
|
|
14
|
-
expect(handleClick).toHaveBeenCalledTimes(1)
|
|
15
|
-
})
|
|
10
|
+
test("calls onClick when clicked", () => {
|
|
11
|
+
const handleClick = jest.fn();
|
|
12
|
+
render(<Button onClick={handleClick}>Click me</Button>);
|
|
13
|
+
fireEvent.click(screen.getByText("Click me"));
|
|
14
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
15
|
+
});
|