@kite-dev/create-plugin-sdk 0.0.1-beta.0 → 0.0.4
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 +174 -13
- package/index.js +164 -37
- package/package.json +12 -5
- package/template/_prettierignore +8 -0
- package/template/eslint.config.js +30 -0
- package/template/plugin.config.tsx +10 -3
- package/template/prettier.config.cjs +10 -0
- package/template/src/i18n.ts +10 -0
- package/template/src/locales/en.json +11 -0
- package/template/src/locales/zh.json +11 -0
- package/template/src/pages/home.tsx +18 -10
- package/template/vite.config.ts +1 -1
- package/template/README.md +0 -20
package/README.md
CHANGED
|
@@ -1,23 +1,105 @@
|
|
|
1
1
|
# Create Kite Plugin
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`@kite-dev/create-plugin-sdk` creates a React and TypeScript plugin for Kite. It includes plugin configuration, a page using Kite UI components, and scripts for building an installable archive.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- Node.js 20.19 or later in the 20.x series, or Node.js 22.12 or later.
|
|
8
|
+
- npm or pnpm.
|
|
9
|
+
- A Kite instance matching the generated plugin's `engines.kite` range, initially `^0.16.0`.
|
|
10
|
+
|
|
11
|
+
## Create a plugin
|
|
12
|
+
|
|
13
|
+
With npm:
|
|
4
14
|
|
|
5
15
|
```sh
|
|
6
|
-
npm create @kite-dev/plugin-sdk
|
|
7
|
-
# 或
|
|
8
|
-
pnpm create @kite-dev/plugin-sdk@beta my-plugin
|
|
16
|
+
npm create @kite-dev/plugin-sdk -- my-plugin
|
|
9
17
|
```
|
|
10
18
|
|
|
11
|
-
|
|
19
|
+
With pnpm:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
pnpm create @kite-dev/plugin-sdk my-plugin
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
These commands run the `@kite-dev/create-plugin-sdk` package. The wizard asks for a display name. Omit the directory argument to choose both the directory and display name interactively.
|
|
26
|
+
|
|
27
|
+
The final directory name becomes the plugin ID. IDs must contain 1–64 lowercase letters, digits, or hyphens, and start and end with a letter or digit. The destination must be empty; an existing `.git` entry is preserved.
|
|
12
28
|
|
|
13
|
-
|
|
29
|
+
### Non-interactive usage
|
|
14
30
|
|
|
15
31
|
```sh
|
|
16
|
-
npm create @kite-dev/plugin-sdk
|
|
17
|
-
|
|
32
|
+
npm create @kite-dev/plugin-sdk -- my-plugin --yes --display-name "My Plugin"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
pnpm create @kite-dev/plugin-sdk my-plugin --yes --display-name "My Plugin"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
| Argument or option | Description |
|
|
40
|
+
| ----------------------- | ---------------------------------------------------------------------------------- |
|
|
41
|
+
| `[directory]` | Destination path, relative to the current directory or absolute. |
|
|
42
|
+
| `--display-name <name>` | Plugin name shown in Kite. Defaults to the directory name in non-interactive mode. |
|
|
43
|
+
| `-y`, `--yes` | Use defaults without prompting. With no directory argument, creates `my-plugin`. |
|
|
44
|
+
| `-h`, `--help` | Display CLI usage. |
|
|
45
|
+
|
|
46
|
+
The creator writes project files and prints the next steps. It does not install dependencies, initialize Git, build the plugin, or publish a package.
|
|
47
|
+
|
|
48
|
+
## Generated project
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
my-plugin/
|
|
52
|
+
├── package.json
|
|
53
|
+
├── plugin.config.tsx
|
|
54
|
+
├── vite.config.ts
|
|
55
|
+
├── tsconfig.json
|
|
56
|
+
├── eslint.config.js
|
|
57
|
+
├── prettier.config.cjs
|
|
58
|
+
├── README.md
|
|
59
|
+
├── .gitignore
|
|
60
|
+
├── .prettierignore
|
|
61
|
+
└── src/
|
|
62
|
+
├── i18n.ts
|
|
63
|
+
├── locales/
|
|
64
|
+
│ ├── en.json
|
|
65
|
+
│ └── zh.json
|
|
66
|
+
└── pages/
|
|
67
|
+
├── home.tsx
|
|
68
|
+
└── home.module.css
|
|
18
69
|
```
|
|
19
70
|
|
|
20
|
-
|
|
71
|
+
- `package.json` defines the plugin ID, display name, version, supported Kite versions, dependencies, and scripts. The generated `engines.kite` range is `^0.16.0`.
|
|
72
|
+
- `plugin.config.tsx` registers the home route and a sidebar entry under **Other** using `definePlugin`.
|
|
73
|
+
- `src/i18n.ts` binds the English and Chinese dictionaries with `createPluginI18n()` and exports `translations`, `label`, and `useTranslation`.
|
|
74
|
+
- `src/locales/en.json` and `src/locales/zh.json` contain navigation and page text. The home label initially uses the chosen display name in both languages.
|
|
75
|
+
- `src/pages/home.tsx` displays Kite's selected cluster and namespace using shared UI components and localized text.
|
|
76
|
+
- `src/pages/home.module.css` contains styles scoped to the page.
|
|
77
|
+
- `vite.config.ts` uses the SDK's build configuration to produce `dist/` and `plugin.json`.
|
|
78
|
+
- `eslint.config.js` checks JavaScript, TypeScript, and React Hooks. `prettier.config.cjs` defines formatting and import ordering.
|
|
79
|
+
- `README.md` starts with the plugin's display name as its heading.
|
|
80
|
+
|
|
81
|
+
Set `package.json.engines.kite` to the Kite versions your plugin supports. The SDK defaults this range to `^0.16.0` if omitted and includes it in the built manifest as `requires.kite`. Kite checks this requirement when managing and loading the plugin.
|
|
82
|
+
|
|
83
|
+
The home page is lazy-loaded. Keep page CSS and browser-specific dependencies in page modules; the plugin configuration is also executed in Node.js to generate navigation metadata.
|
|
84
|
+
|
|
85
|
+
## Localize a plugin
|
|
86
|
+
|
|
87
|
+
Add matching translation keys to `src/locales/en.json` and `src/locales/zh.json`. The generated configuration registers `i18n: translations` and uses `label('navigation.home')` for its route title and menu label.
|
|
88
|
+
|
|
89
|
+
Inside a page, import the generated hook:
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
import { useTranslation } from '../i18n'
|
|
93
|
+
|
|
94
|
+
export function ContextHeading() {
|
|
95
|
+
const { t } = useTranslation()
|
|
96
|
+
return <h2>{t('context.description')}</h2>
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Both `label()` and `t()` provide completion for your locale keys. Use `t('key', { name })` for a message containing `{{name}}`. The hook also returns the current `language`. Navigation and page text follow Kite's language selection; namespace registration is handled by Kite.
|
|
101
|
+
|
|
102
|
+
## Build and install
|
|
21
103
|
|
|
22
104
|
```sh
|
|
23
105
|
cd my-plugin
|
|
@@ -26,10 +108,89 @@ pnpm run build
|
|
|
26
108
|
pnpm run pack
|
|
27
109
|
```
|
|
28
110
|
|
|
29
|
-
|
|
111
|
+
You can use `npm install`, `npm run build`, and `npm run pack` instead.
|
|
112
|
+
|
|
113
|
+
The package is written to `<id>-<version>.tar.gz` in the plugin directory. In Kite, open the avatar menu, select **Plugin management**, and use **Install from file** to upload it. Plugin installation requires a Kite administrator. Once installed, open the plugin from **Other** in the sidebar.
|
|
114
|
+
|
|
115
|
+
| Script | Action |
|
|
116
|
+
| -------------- | ---------------------------------------------------------- |
|
|
117
|
+
| `type-check` | Check TypeScript without producing output. |
|
|
118
|
+
| `build` | Type-check and build the plugin into `dist/`. |
|
|
119
|
+
| `dev` | Watch source files and rebuild `dist/`. |
|
|
120
|
+
| `pack` | Package the existing `dist/` directory. Run `build` first. |
|
|
121
|
+
| `lint` | Check JavaScript, TypeScript, and React Hooks with ESLint. |
|
|
122
|
+
| `lint:fix` | Apply automatic ESLint fixes. |
|
|
123
|
+
| `format` | Format source files and sort imports with Prettier. |
|
|
124
|
+
| `format:check` | Check formatting without changing files. |
|
|
125
|
+
|
|
126
|
+
Plugin pages run inside Kite. Watch mode does not serve a standalone application or install rebuilt files. Increment `package.json.version`, rebuild, and install a new package to update a plugin. Restart the watch command after changing its ID or version.
|
|
30
127
|
|
|
31
|
-
|
|
128
|
+
See the [SDK documentation](../README.md) for resource APIs, navigation, components, styling, and plugin configuration.
|
|
32
129
|
|
|
33
|
-
##
|
|
130
|
+
## Create a plugin in a pnpm workspace
|
|
131
|
+
|
|
132
|
+
From a workspace whose `pnpm-workspace.yaml` includes `plugins/*`:
|
|
133
|
+
|
|
134
|
+
```sh
|
|
135
|
+
pnpm create @kite-dev/plugin-sdk plugins/my-plugin
|
|
136
|
+
pnpm install
|
|
137
|
+
pnpm --filter my-plugin run build
|
|
138
|
+
pnpm --filter my-plugin run pack
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The creator writes into the selected directory. Workspace package discovery and dependency installation are managed by pnpm.
|
|
142
|
+
|
|
143
|
+
The creator detects the nearest ancestor containing `pnpm-workspace.yaml` or `package.json.workspaces`. If that root already provides an ESLint or Prettier configuration, the new plugin reuses the corresponding root configuration and dependencies. Each tool is detected independently; missing tooling is included with the new plugin. The creator does not change workspace configuration.
|
|
144
|
+
|
|
145
|
+
For shared tooling, run the workspace's quality commands from its root so its file patterns and ignore rules apply consistently:
|
|
146
|
+
|
|
147
|
+
```sh
|
|
148
|
+
pnpm run lint
|
|
149
|
+
pnpm run format:check
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The plugin also includes `lint`, `lint:fix`, `format`, and `format:check` scripts. An npm workspace uses the same configuration reuse behavior.
|
|
153
|
+
|
|
154
|
+
## Develop the creator locally
|
|
155
|
+
|
|
156
|
+
From the `kite-plugin-sdk` repository root:
|
|
157
|
+
|
|
158
|
+
```sh
|
|
159
|
+
pnpm install --frozen-lockfile
|
|
160
|
+
pnpm run build
|
|
161
|
+
cd create-plugin-sdk
|
|
162
|
+
pnpm run dev ../../my-plugin --yes --display-name "My Plugin"
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The destination in this example is a new `my-plugin` directory beside the SDK repository. Choose an empty destination for each run. `pnpm run dev` executes `index.js` directly, so edits to the CLI or `template/` are used on the next invocation.
|
|
166
|
+
|
|
167
|
+
To build the generated plugin against the same SDK checkout:
|
|
168
|
+
|
|
169
|
+
```sh
|
|
170
|
+
cd ../../my-plugin
|
|
171
|
+
pnpm install
|
|
172
|
+
pnpm add @kite-dev/plugin-sdk@file:../kite-plugin-sdk
|
|
173
|
+
pnpm run build
|
|
174
|
+
pnpm run pack
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
For breakpoint debugging, run this from `create-plugin-sdk/`:
|
|
178
|
+
|
|
179
|
+
```sh
|
|
180
|
+
node --inspect-brk index.js ../../my-plugin
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Attach your debugger to the Node.js process. Running the local entry point uses your source checkout; `npm create` and `pnpm create` use the published creator.
|
|
184
|
+
|
|
185
|
+
## Releases
|
|
186
|
+
|
|
187
|
+
The creator and SDK share the same version and are released together. The pnpm workspace links the creator's `workspace:*` dependency to the local SDK checkout during development. `pnpm pack` converts it to the exact SDK version in the published package.
|
|
188
|
+
|
|
189
|
+
From the repository root, with all changes committed:
|
|
190
|
+
|
|
191
|
+
```sh
|
|
192
|
+
./scripts/release.sh 0.0.4
|
|
193
|
+
git push --atomic origin HEAD v0.0.4
|
|
194
|
+
```
|
|
34
195
|
|
|
35
|
-
|
|
196
|
+
The script updates both package versions and the shared lockfile, then creates a release commit and tag. Pushing the tag triggers `publish.yml`, which packs both packages with pnpm and publishes the SDK followed by the creator. Stable versions use the `latest` npm tag; prerelease versions use `beta`.
|
package/index.js
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
cpSync,
|
|
4
|
+
existsSync,
|
|
5
|
+
lstatSync,
|
|
6
|
+
mkdirSync,
|
|
7
|
+
readdirSync,
|
|
8
|
+
readFileSync,
|
|
9
|
+
renameSync,
|
|
10
|
+
writeFileSync,
|
|
11
|
+
} from 'node:fs'
|
|
12
|
+
import { basename, dirname, resolve } from 'node:path'
|
|
4
13
|
import { fileURLToPath } from 'node:url'
|
|
5
14
|
import { parseArgs } from 'node:util'
|
|
6
15
|
import * as prompts from '@clack/prompts'
|
|
@@ -15,8 +24,8 @@ Options:
|
|
|
15
24
|
-h, --help Show this help
|
|
16
25
|
|
|
17
26
|
Examples:
|
|
18
|
-
npm create @kite-dev/plugin-sdk
|
|
19
|
-
pnpm create @kite-dev/plugin-sdk
|
|
27
|
+
npm create @kite-dev/plugin-sdk my-plugin
|
|
28
|
+
pnpm create @kite-dev/plugin-sdk my-plugin`
|
|
20
29
|
|
|
21
30
|
function metadataError(id, name) {
|
|
22
31
|
try {
|
|
@@ -25,7 +34,7 @@ function metadataError(id, name) {
|
|
|
25
34
|
id,
|
|
26
35
|
name,
|
|
27
36
|
version: '0.1.0',
|
|
28
|
-
requires: {
|
|
37
|
+
requires: { kite: '^0.16.0' },
|
|
29
38
|
entry: 'mf-manifest.json',
|
|
30
39
|
module: './plugin',
|
|
31
40
|
routes: [],
|
|
@@ -41,8 +50,55 @@ function directoryError(directory) {
|
|
|
41
50
|
const error = metadataError(basename(target), 'Plugin')
|
|
42
51
|
if (error) return error
|
|
43
52
|
if (existsSync(target)) {
|
|
44
|
-
if (!lstatSync(target).isDirectory())
|
|
45
|
-
|
|
53
|
+
if (!lstatSync(target).isDirectory())
|
|
54
|
+
return 'The target path must be a directory.'
|
|
55
|
+
if (readdirSync(target).some((entry) => entry !== '.git'))
|
|
56
|
+
return 'The target directory is not empty. Choose an empty directory.'
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function workspaceTooling(target) {
|
|
61
|
+
let directory = dirname(target)
|
|
62
|
+
while (true) {
|
|
63
|
+
const packagePath = resolve(directory, 'package.json')
|
|
64
|
+
const metadata = existsSync(packagePath)
|
|
65
|
+
? JSON.parse(readFileSync(packagePath, 'utf8'))
|
|
66
|
+
: {}
|
|
67
|
+
if (
|
|
68
|
+
existsSync(resolve(directory, 'pnpm-workspace.yaml')) ||
|
|
69
|
+
Array.isArray(metadata.workspaces) ||
|
|
70
|
+
Array.isArray(metadata.workspaces?.packages)
|
|
71
|
+
) {
|
|
72
|
+
const eslint = ['js', 'mjs', 'cjs', 'ts', 'mts', 'cts'].some(
|
|
73
|
+
(extension) =>
|
|
74
|
+
existsSync(resolve(directory, `eslint.config.${extension}`))
|
|
75
|
+
)
|
|
76
|
+
const prettier =
|
|
77
|
+
metadata.prettier !== undefined ||
|
|
78
|
+
[
|
|
79
|
+
'.prettierrc',
|
|
80
|
+
...[
|
|
81
|
+
'json',
|
|
82
|
+
'json5',
|
|
83
|
+
'yaml',
|
|
84
|
+
'yml',
|
|
85
|
+
'toml',
|
|
86
|
+
'js',
|
|
87
|
+
'cjs',
|
|
88
|
+
'mjs',
|
|
89
|
+
'ts',
|
|
90
|
+
'cts',
|
|
91
|
+
'mts',
|
|
92
|
+
].map((extension) => `.prettierrc.${extension}`),
|
|
93
|
+
...['js', 'cjs', 'mjs', 'ts', 'cts', 'mts'].map(
|
|
94
|
+
(extension) => `prettier.config.${extension}`
|
|
95
|
+
),
|
|
96
|
+
].some((file) => existsSync(resolve(directory, file)))
|
|
97
|
+
return { eslint, prettier }
|
|
98
|
+
}
|
|
99
|
+
const parent = dirname(directory)
|
|
100
|
+
if (parent === directory) return { eslint: false, prettier: false }
|
|
101
|
+
directory = parent
|
|
46
102
|
}
|
|
47
103
|
}
|
|
48
104
|
|
|
@@ -62,7 +118,9 @@ async function main() {
|
|
|
62
118
|
if (positionals.length > 1) throw new Error(usage)
|
|
63
119
|
const interactive = process.stdin.isTTY && process.stdout.isTTY && !values.yes
|
|
64
120
|
if (!interactive && !positionals[0] && !values.yes) {
|
|
65
|
-
throw new Error(
|
|
121
|
+
throw new Error(
|
|
122
|
+
'Specify a project directory or use --yes to create my-plugin.'
|
|
123
|
+
)
|
|
66
124
|
}
|
|
67
125
|
if (positionals[0]) {
|
|
68
126
|
const error = directoryError(positionals[0])
|
|
@@ -70,27 +128,41 @@ async function main() {
|
|
|
70
128
|
}
|
|
71
129
|
|
|
72
130
|
prompts.intro('Create a Kite plugin')
|
|
73
|
-
const answers = await prompts.group(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
131
|
+
const answers = await prompts.group(
|
|
132
|
+
{
|
|
133
|
+
directory: async () =>
|
|
134
|
+
positionals[0] ??
|
|
135
|
+
(interactive
|
|
136
|
+
? prompts.text({
|
|
137
|
+
message: 'Project directory',
|
|
138
|
+
initialValue: 'my-plugin',
|
|
139
|
+
validate: (value) =>
|
|
140
|
+
value?.trim()
|
|
141
|
+
? directoryError(value.trim())
|
|
142
|
+
: 'Enter a project directory.',
|
|
143
|
+
})
|
|
144
|
+
: 'my-plugin'),
|
|
145
|
+
displayName: async ({ results }) =>
|
|
146
|
+
values['display-name'] ??
|
|
147
|
+
(interactive
|
|
148
|
+
? prompts.text({
|
|
149
|
+
message: 'Plugin display name',
|
|
150
|
+
initialValue: basename(resolve(results.directory.trim())),
|
|
151
|
+
validate: (value) =>
|
|
152
|
+
metadataError(
|
|
153
|
+
basename(resolve(results.directory.trim())),
|
|
154
|
+
value?.trim()
|
|
155
|
+
),
|
|
156
|
+
})
|
|
157
|
+
: basename(resolve(results.directory.trim()))),
|
|
92
158
|
},
|
|
93
|
-
|
|
159
|
+
{
|
|
160
|
+
onCancel: () => {
|
|
161
|
+
prompts.cancel('Plugin creation cancelled.')
|
|
162
|
+
process.exit(0)
|
|
163
|
+
},
|
|
164
|
+
}
|
|
165
|
+
)
|
|
94
166
|
|
|
95
167
|
const directory = answers.directory.trim()
|
|
96
168
|
const target = resolve(directory)
|
|
@@ -99,6 +171,21 @@ async function main() {
|
|
|
99
171
|
const error = directoryError(directory) ?? metadataError(id, displayName)
|
|
100
172
|
if (error) throw new Error(error)
|
|
101
173
|
|
|
174
|
+
const sharedTooling = workspaceTooling(target)
|
|
175
|
+
const toolingDependencies = [
|
|
176
|
+
...(sharedTooling.eslint
|
|
177
|
+
? []
|
|
178
|
+
: [
|
|
179
|
+
'@eslint/js',
|
|
180
|
+
'eslint',
|
|
181
|
+
'eslint-plugin-react-hooks',
|
|
182
|
+
'globals',
|
|
183
|
+
'typescript-eslint',
|
|
184
|
+
]),
|
|
185
|
+
...(sharedTooling.prettier
|
|
186
|
+
? []
|
|
187
|
+
: ['@ianvs/prettier-plugin-sort-imports', 'prettier']),
|
|
188
|
+
]
|
|
102
189
|
const metadata = {
|
|
103
190
|
name: id,
|
|
104
191
|
displayName,
|
|
@@ -107,11 +194,16 @@ async function main() {
|
|
|
107
194
|
type: 'module',
|
|
108
195
|
license: 'Apache-2.0',
|
|
109
196
|
description: '',
|
|
197
|
+
engines: { kite: '^0.16.0' },
|
|
110
198
|
scripts: {
|
|
111
199
|
'type-check': 'tsc --noEmit',
|
|
112
200
|
build: 'tsc --noEmit && vite build',
|
|
113
201
|
dev: 'vite build --watch',
|
|
114
202
|
pack: 'kite-plugin pack',
|
|
203
|
+
lint: 'eslint .',
|
|
204
|
+
'lint:fix': 'eslint . --fix',
|
|
205
|
+
format: 'prettier --write .',
|
|
206
|
+
'format:check': 'prettier --check .',
|
|
115
207
|
},
|
|
116
208
|
dependencies: {
|
|
117
209
|
[sdk.name]: sdk.version,
|
|
@@ -125,6 +217,9 @@ async function main() {
|
|
|
125
217
|
'@types/react-dom': sdk.devDependencies['@types/react-dom'],
|
|
126
218
|
typescript: sdk.devDependencies.typescript,
|
|
127
219
|
vite: sdk.peerDependencies.vite,
|
|
220
|
+
...Object.fromEntries(
|
|
221
|
+
toolingDependencies.map((name) => [name, sdk.devDependencies[name]])
|
|
222
|
+
),
|
|
128
223
|
},
|
|
129
224
|
}
|
|
130
225
|
mkdirSync(target, { recursive: true })
|
|
@@ -132,18 +227,50 @@ async function main() {
|
|
|
132
227
|
recursive: true,
|
|
133
228
|
force: false,
|
|
134
229
|
errorOnExist: true,
|
|
230
|
+
filter: (source) =>
|
|
231
|
+
!(sharedTooling.eslint && basename(source) === 'eslint.config.js') &&
|
|
232
|
+
!(
|
|
233
|
+
sharedTooling.prettier &&
|
|
234
|
+
['prettier.config.cjs', '_prettierignore'].includes(basename(source))
|
|
235
|
+
),
|
|
135
236
|
})
|
|
136
237
|
renameSync(resolve(target, '_gitignore'), resolve(target, '.gitignore'))
|
|
137
|
-
|
|
238
|
+
if (!sharedTooling.prettier) {
|
|
239
|
+
renameSync(
|
|
240
|
+
resolve(target, '_prettierignore'),
|
|
241
|
+
resolve(target, '.prettierignore')
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
for (const language of ['en', 'zh']) {
|
|
245
|
+
const localePath = resolve(target, 'src/locales', `${language}.json`)
|
|
246
|
+
const dictionary = JSON.parse(readFileSync(localePath, 'utf8'))
|
|
247
|
+
dictionary.navigation.home = displayName
|
|
248
|
+
writeFileSync(localePath, `${JSON.stringify(dictionary, null, 2)}\n`)
|
|
249
|
+
}
|
|
250
|
+
writeFileSync(
|
|
251
|
+
resolve(target, 'package.json'),
|
|
252
|
+
`${JSON.stringify(metadata, null, 2)}\n`,
|
|
253
|
+
{ flag: 'wx' }
|
|
254
|
+
)
|
|
255
|
+
writeFileSync(resolve(target, 'README.md'), `# ${displayName}\n`, {
|
|
256
|
+
flag: 'wx',
|
|
257
|
+
})
|
|
138
258
|
|
|
139
|
-
const manager = process.env.npm_config_user_agent?.startsWith('pnpm/')
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
259
|
+
const manager = process.env.npm_config_user_agent?.startsWith('pnpm/')
|
|
260
|
+
? 'pnpm'
|
|
261
|
+
: 'npm'
|
|
262
|
+
prompts.note(
|
|
263
|
+
[
|
|
264
|
+
`cd '${directory.replaceAll("'", "'\\''")}'`,
|
|
265
|
+
`${manager} install`,
|
|
266
|
+
`${manager} run build`,
|
|
267
|
+
`${manager} run pack`,
|
|
268
|
+
].join('\n'),
|
|
269
|
+
'Next steps'
|
|
270
|
+
)
|
|
271
|
+
prompts.outro(
|
|
272
|
+
`Created ${displayName}. Upload the built archive in Kite → Plugin management.`
|
|
273
|
+
)
|
|
147
274
|
}
|
|
148
275
|
|
|
149
276
|
main().catch((error) => {
|
package/package.json
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kite-dev/create-plugin-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Create a Kite frontend plugin",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/kite-org/plugin-sdk.git",
|
|
10
|
+
"directory": "create-plugin-sdk"
|
|
11
|
+
},
|
|
7
12
|
"engines": {
|
|
8
13
|
"node": "^20.19.0 || >=22.12.0"
|
|
9
14
|
},
|
|
@@ -17,11 +22,13 @@
|
|
|
17
22
|
],
|
|
18
23
|
"dependencies": {
|
|
19
24
|
"@clack/prompts": "1.8.0",
|
|
20
|
-
"@kite-dev/plugin-sdk": "0.0.
|
|
25
|
+
"@kite-dev/plugin-sdk": "0.0.4"
|
|
21
26
|
},
|
|
22
27
|
"publishConfig": {
|
|
23
28
|
"registry": "https://registry.npmjs.org/",
|
|
24
|
-
"access": "public"
|
|
25
|
-
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"dev": "node index.js"
|
|
26
33
|
}
|
|
27
|
-
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import js from '@eslint/js'
|
|
2
|
+
import reactHooks from 'eslint-plugin-react-hooks'
|
|
3
|
+
import globals from 'globals'
|
|
4
|
+
import tseslint from 'typescript-eslint'
|
|
5
|
+
|
|
6
|
+
export default tseslint.config(
|
|
7
|
+
{
|
|
8
|
+
ignores: [
|
|
9
|
+
'**/node_modules/**',
|
|
10
|
+
'**/dist/**',
|
|
11
|
+
'**/.vite/**',
|
|
12
|
+
'**/__mf__virtual/**',
|
|
13
|
+
],
|
|
14
|
+
},
|
|
15
|
+
js.configs.recommended,
|
|
16
|
+
...tseslint.configs.recommended,
|
|
17
|
+
{
|
|
18
|
+
files: ['src/**/*.{ts,tsx}', 'plugin.config.tsx'],
|
|
19
|
+
languageOptions: { globals: globals.browser },
|
|
20
|
+
plugins: { 'react-hooks': reactHooks },
|
|
21
|
+
rules: {
|
|
22
|
+
'react-hooks/rules-of-hooks': 'error',
|
|
23
|
+
'react-hooks/exhaustive-deps': 'warn',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
files: ['vite.config.ts', 'eslint.config.js', 'prettier.config.cjs'],
|
|
28
|
+
languageOptions: { globals: globals.node },
|
|
29
|
+
}
|
|
30
|
+
)
|
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
import { lazy } from 'react'
|
|
2
2
|
import { definePlugin } from '@kite-dev/plugin-sdk'
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
import { label, translations } from './src/i18n'
|
|
4
5
|
|
|
5
6
|
const HomePage = lazy(() => import('./src/pages/home'))
|
|
6
7
|
|
|
7
8
|
export default definePlugin({
|
|
9
|
+
i18n: translations,
|
|
8
10
|
routes: [
|
|
9
|
-
{
|
|
11
|
+
{
|
|
12
|
+
id: 'home',
|
|
13
|
+
path: '',
|
|
14
|
+
title: label('navigation.home'),
|
|
15
|
+
element: <HomePage />,
|
|
16
|
+
},
|
|
10
17
|
],
|
|
11
18
|
menus: [
|
|
12
19
|
{
|
|
13
20
|
id: 'home',
|
|
14
21
|
parent: 'core:other',
|
|
15
|
-
label:
|
|
22
|
+
label: label('navigation.home'),
|
|
16
23
|
route: 'home',
|
|
17
24
|
icon: 'IconBox',
|
|
18
25
|
},
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
endOfLine: 'lf',
|
|
3
|
+
semi: false,
|
|
4
|
+
singleQuote: true,
|
|
5
|
+
tabWidth: 2,
|
|
6
|
+
trailingComma: 'es5',
|
|
7
|
+
importOrder: ['^react(?:/.*)?$', '<THIRD_PARTY_MODULES>', '', '^[./]'],
|
|
8
|
+
importOrderParserPlugins: ['typescript', 'jsx', 'decorators-legacy'],
|
|
9
|
+
plugins: ['@ianvs/prettier-plugin-sort-imports'],
|
|
10
|
+
}
|
|
@@ -1,27 +1,35 @@
|
|
|
1
|
-
import { useCluster, useNamespace } from '@kite-dev/plugin-sdk'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { useCluster, useNamespace } from '@kite-dev/plugin-sdk/hooks'
|
|
2
|
+
import {
|
|
3
|
+
Card,
|
|
4
|
+
CardContent,
|
|
5
|
+
CardDescription,
|
|
6
|
+
CardHeader,
|
|
7
|
+
CardTitle,
|
|
8
|
+
} from '@kite-dev/plugin-sdk/ui'
|
|
9
|
+
|
|
10
|
+
import { useTranslation } from '../i18n'
|
|
5
11
|
import styles from './home.module.css'
|
|
6
12
|
|
|
7
13
|
export default function HomePage() {
|
|
8
14
|
const { currentCluster } = useCluster()
|
|
9
15
|
const { namespace } = useNamespace()
|
|
10
|
-
const { t } =
|
|
16
|
+
const { t } = useTranslation()
|
|
11
17
|
|
|
12
18
|
return (
|
|
13
19
|
<main className={styles.page}>
|
|
14
20
|
<Card>
|
|
15
21
|
<CardHeader>
|
|
16
|
-
<CardTitle>{
|
|
17
|
-
<CardDescription>{t(
|
|
22
|
+
<CardTitle>{t('navigation.home')}</CardTitle>
|
|
23
|
+
<CardDescription>{t('context.description')}</CardDescription>
|
|
18
24
|
</CardHeader>
|
|
19
25
|
<CardContent>
|
|
20
26
|
<dl className={styles.context}>
|
|
21
|
-
<dt>{t(
|
|
27
|
+
<dt>{t('context.cluster')}</dt>
|
|
22
28
|
<dd>{currentCluster ?? '—'}</dd>
|
|
23
|
-
<dt>{t(
|
|
24
|
-
<dd>
|
|
29
|
+
<dt>{t('context.namespace')}</dt>
|
|
30
|
+
<dd>
|
|
31
|
+
{namespace === '_all' ? t('context.allNamespaces') : namespace}
|
|
32
|
+
</dd>
|
|
25
33
|
</dl>
|
|
26
34
|
</CardContent>
|
|
27
35
|
</Card>
|
package/template/vite.config.ts
CHANGED
package/template/README.md
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# Kite Plugin
|
|
2
|
-
|
|
3
|
-
在生成的插件目录安装依赖、构建并打包:
|
|
4
|
-
|
|
5
|
-
```sh
|
|
6
|
-
npm install
|
|
7
|
-
npm run build
|
|
8
|
-
npm run pack
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
打包后得到 `<插件 ID>-<版本>.tar.gz`。在 Kite 头像菜单进入「插件」,上传安装包;启用后可在「其他」分组打开插件首页。
|
|
12
|
-
|
|
13
|
-
- `package.json`:插件 ID、展示名称、版本和依赖。首页标题及菜单名称复用 `displayName`。
|
|
14
|
-
- `plugin.config.tsx`:使用 `definePlugin` 注册路由和菜单,直接绑定 JSX。
|
|
15
|
-
- `src/pages/home.tsx`:首页复用宿主 UI、语言、集群和命名空间上下文。
|
|
16
|
-
- `src/pages/home.module.css`:插件自身布局样式。
|
|
17
|
-
|
|
18
|
-
SDK 构建时自动生成导航清单;页面使用 `React.lazy`,首次访问时才加载。配置需要能在 Node 中执行,CSS、浏览器 API 和页面依赖留在 lazy 导入的页面模块中。
|
|
19
|
-
|
|
20
|
-
插件需要在兼容的 Kite 宿主中运行,没有独立的开发网页。修改后重新构建、打包并安装;更新已安装插件时先递增 `package.json` 的版本。
|