create-halo-plugin-template 1.0.0 → 1.0.1

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.
Files changed (108) hide show
  1. package/.editorconfig +520 -0
  2. package/.github/workflows/cd.yaml +20 -0
  3. package/.github/workflows/ci.yaml +32 -0
  4. package/.github/workflows/publish-npm.yaml +46 -0
  5. package/.gitignore +84 -0
  6. package/LICENSE +674 -0
  7. package/README.md +191 -0
  8. package/build.gradle +103 -0
  9. package/docs/first-npm-release-checklist.md +58 -0
  10. package/docs/publish-template.md +148 -0
  11. package/docs/rsbuild-switch.md +90 -0
  12. package/docs/template-pruning.md +43 -0
  13. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  14. package/gradle/wrapper/gradle-wrapper.properties +7 -0
  15. package/gradle.properties +1 -0
  16. package/gradlew +248 -0
  17. package/gradlew.bat +93 -0
  18. package/package.json +67 -7
  19. package/scripts/create-project.mjs +399 -0
  20. package/scripts/init-template.mjs +281 -0
  21. package/scripts/publish-check.mjs +97 -0
  22. package/scripts/release.mjs +278 -0
  23. package/scripts/verify-template.mjs +407 -0
  24. package/settings.gradle +7 -0
  25. package/src/main/java/run/halo/plugintemplate/PluginTemplatePlugin.java +43 -0
  26. package/src/main/java/run/halo/plugintemplate/config/PluginTemplateConfig.java +14 -0
  27. package/src/main/java/run/halo/plugintemplate/dto/PluginTemplateChecklistItem.java +30 -0
  28. package/src/main/java/run/halo/plugintemplate/dto/PluginTemplateFeatureItem.java +30 -0
  29. package/src/main/java/run/halo/plugintemplate/dto/PluginTemplateOverview.java +73 -0
  30. package/src/main/java/run/halo/plugintemplate/dto/PluginTemplateStatItem.java +30 -0
  31. package/src/main/java/run/halo/plugintemplate/endpoint/PluginTemplateConsoleEndpoint.java +33 -0
  32. package/src/main/java/run/halo/plugintemplate/endpoint/PluginTemplatePublicEndpoint.java +26 -0
  33. package/src/main/java/run/halo/plugintemplate/endpoint/PluginTemplateUcEndpoint.java +33 -0
  34. package/src/main/java/run/halo/plugintemplate/endpoint/routes/PluginTemplateOverviewRoutes.java +60 -0
  35. package/src/main/java/run/halo/plugintemplate/model/PluginTemplateAudience.java +23 -0
  36. package/src/main/java/run/halo/plugintemplate/query/PluginTemplateOverviewQuery.java +26 -0
  37. package/src/main/java/run/halo/plugintemplate/reconcile/PluginTemplateSettingsReconciler.java +17 -0
  38. package/src/main/java/run/halo/plugintemplate/scheme/PluginTemplateRecord.java +43 -0
  39. package/src/main/java/run/halo/plugintemplate/service/PluginTemplateOverviewService.java +10 -0
  40. package/src/main/java/run/halo/plugintemplate/service/impl/PluginTemplateOverviewServiceImpl.java +74 -0
  41. package/src/main/java/run/halo/plugintemplate/setting/PluginTemplateGeneralSetting.java +25 -0
  42. package/src/main/java/run/halo/plugintemplate/setting/PluginTemplateSettingKeys.java +24 -0
  43. package/src/main/java/run/halo/plugintemplate/setting/PluginTemplateUiSetting.java +13 -0
  44. package/src/main/java/run/halo/plugintemplate/utils/PluginTemplateSeeds.java +197 -0
  45. package/src/main/resources/extensions/roleTemplate-console.yaml +39 -0
  46. package/src/main/resources/extensions/roleTemplate-uc.yaml +19 -0
  47. package/src/main/resources/extensions/settings.yaml +47 -0
  48. package/src/main/resources/logo.png +0 -0
  49. package/src/main/resources/plugin.yaml +24 -0
  50. package/src/test/java/run/halo/plugintemplate/PluginTemplatePluginTest.java +34 -0
  51. package/src/test/java/run/halo/plugintemplate/service/impl/PluginTemplateOverviewServiceImplTest.java +97 -0
  52. package/ui/build.gradle +41 -0
  53. package/ui/env.d.ts +2 -0
  54. package/ui/eslint.config.ts +30 -0
  55. package/ui/package.json +57 -0
  56. package/ui/pnpm-lock.yaml +5250 -0
  57. package/ui/src/api/__tests__/normalizers.spec.ts +65 -0
  58. package/ui/src/api/generated/.openapi-generator/FILES +23 -0
  59. package/ui/src/api/generated/.openapi-generator/VERSION +1 -0
  60. package/ui/src/api/generated/.openapi-generator-ignore +23 -0
  61. package/ui/src/api/generated/api/plugin-template-console-api.ts +128 -0
  62. package/ui/src/api/generated/api/plugin-template-uc-api.ts +128 -0
  63. package/ui/src/api/generated/api.ts +19 -0
  64. package/ui/src/api/generated/base.ts +86 -0
  65. package/ui/src/api/generated/common.ts +150 -0
  66. package/ui/src/api/generated/configuration.ts +110 -0
  67. package/ui/src/api/generated/git_push.sh +57 -0
  68. package/ui/src/api/generated/index.ts +18 -0
  69. package/ui/src/api/generated/models/add-operation.ts +49 -0
  70. package/ui/src/api/generated/models/copy-operation.ts +49 -0
  71. package/ui/src/api/generated/models/index.ts +11 -0
  72. package/ui/src/api/generated/models/json-patch-inner.ts +41 -0
  73. package/ui/src/api/generated/models/move-operation.ts +49 -0
  74. package/ui/src/api/generated/models/plugin-template-checklist-item.ts +54 -0
  75. package/ui/src/api/generated/models/plugin-template-feature-item.ts +54 -0
  76. package/ui/src/api/generated/models/plugin-template-overview.ts +147 -0
  77. package/ui/src/api/generated/models/plugin-template-stat-item.ts +54 -0
  78. package/ui/src/api/generated/models/remove-operation.ts +43 -0
  79. package/ui/src/api/generated/models/replace-operation.ts +49 -0
  80. package/ui/src/api/generated/models/test-operation.ts +49 -0
  81. package/ui/src/api/index.ts +42 -0
  82. package/ui/src/api/normalizers.ts +65 -0
  83. package/ui/src/assets/element.scss +24 -0
  84. package/ui/src/assets/index.css +361 -0
  85. package/ui/src/assets/logo.svg +1 -0
  86. package/ui/src/components/PluginTemplateAttachmentTab.vue +69 -0
  87. package/ui/src/components/PluginTemplateCommonTable.vue +69 -0
  88. package/ui/src/components/PluginTemplateDashboardWidget.vue +62 -0
  89. package/ui/src/components/PluginTemplateOverviewPage.vue +254 -0
  90. package/ui/src/components/ui/PluginUiProvider.vue +40 -0
  91. package/ui/src/components/ui/UiMetricCard.vue +21 -0
  92. package/ui/src/components/ui/UiSectionCard.vue +25 -0
  93. package/ui/src/components/ui/UiStatusPill.vue +18 -0
  94. package/ui/src/composables/useTemplateOverview.ts +38 -0
  95. package/ui/src/index.ts +88 -0
  96. package/ui/src/lib/__tests__/plugin-ui.spec.ts +19 -0
  97. package/ui/src/lib/plugin-ui.ts +19 -0
  98. package/ui/src/lib/template.spec.ts +24 -0
  99. package/ui/src/lib/template.ts +52 -0
  100. package/ui/src/lib/theme.ts +31 -0
  101. package/ui/src/types/index.ts +59 -0
  102. package/ui/src/views/console/ConsoleDashboardView.vue +7 -0
  103. package/ui/src/views/uc/UcDashboardView.vue +7 -0
  104. package/ui/tsconfig.app.json +12 -0
  105. package/ui/tsconfig.json +14 -0
  106. package/ui/tsconfig.node.json +15 -0
  107. package/ui/tsconfig.vitest.json +11 -0
  108. package/ui/vite.config.ts +25 -0
@@ -0,0 +1,47 @@
1
+ apiVersion: v1alpha1
2
+ kind: Setting
3
+ metadata:
4
+ name: halo-plugin-template-settings
5
+ spec:
6
+ forms:
7
+ - group: general
8
+ label: 通用设置
9
+ formSchema:
10
+ - $formkit: switch
11
+ name: enableConsoleDashboard
12
+ label: 启用 Console 工作台
13
+ value: true
14
+ help: 控制插件默认 Console 页面和仪表盘小部件是否启用。
15
+ - $formkit: switch
16
+ name: enableUcDashboard
17
+ label: 启用 UC 页面
18
+ value: true
19
+ help: 控制插件是否向 Halo UC 注册默认示例页面。
20
+ - $formkit: switch
21
+ name: enableAttachmentProvider
22
+ label: 启用附件扩展标签页
23
+ value: true
24
+ help: 开启后在附件选择器里显示模板扩展示例。
25
+ - group: ui
26
+ label: 界面主题
27
+ formSchema:
28
+ - $formkit: color
29
+ name: accentColor
30
+ label: 主色
31
+ value: "#2457F5"
32
+ - $formkit: radio
33
+ name: density
34
+ label: 页面密度
35
+ value: balanced
36
+ options:
37
+ - value: compact
38
+ label: 紧凑
39
+ - value: balanced
40
+ label: 平衡
41
+ - value: relaxed
42
+ label: 宽松
43
+ - $formkit: text
44
+ name: supportLink
45
+ label: 支持地址
46
+ value: "https://docs.halo.run/developer-guide/plugin/introduction"
47
+ help: 模板页右上角默认按钮可直接跳转到该地址。
Binary file
@@ -0,0 +1,24 @@
1
+ # Refer https://docs.halo.run/developer-guide/plugin/basics/manifest
2
+
3
+ apiVersion: plugin.halo.run/v1alpha1
4
+ kind: Plugin
5
+ metadata:
6
+ # The name defines how the plugin is invoked, A unique name
7
+ name: halo-plugin-template
8
+ spec:
9
+ enabled: true
10
+ requires: ">=2.23.0"
11
+ author:
12
+ name: Template Author
13
+ website: https://github.com/example
14
+ logo: logo.png
15
+ settingName: halo-plugin-template-settings
16
+ configMapName: halo-plugin-template-configmap
17
+ homepage: https://github.com/example/halo-plugin-template#readme
18
+ repo: https://github.com/example/halo-plugin-template
19
+ issues: https://github.com/example/halo-plugin-template/issues
20
+ displayName: "Halo Plugin Template"
21
+ description: "Halo plugin starter with Vite, Element Plus, extension points, and an initialization script."
22
+ license:
23
+ - name: "GPL-3.0"
24
+ url: "https://github.com/example/halo-plugin-template/blob/main/LICENSE"
@@ -0,0 +1,34 @@
1
+ package run.halo.plugintemplate;
2
+
3
+ import static org.mockito.ArgumentMatchers.any;
4
+ import static org.mockito.ArgumentMatchers.eq;
5
+ import static org.mockito.Mockito.verify;
6
+
7
+ import org.junit.jupiter.api.Test;
8
+ import org.junit.jupiter.api.extension.ExtendWith;
9
+ import org.mockito.Mock;
10
+ import org.mockito.junit.jupiter.MockitoExtension;
11
+ import run.halo.app.extension.SchemeManager;
12
+ import run.halo.app.plugin.PluginContext;
13
+ import run.halo.plugintemplate.scheme.PluginTemplateRecord;
14
+
15
+ @ExtendWith(MockitoExtension.class)
16
+ class PluginTemplatePluginTest {
17
+
18
+ @Mock
19
+ PluginContext context;
20
+
21
+ @Mock
22
+ SchemeManager schemeManager;
23
+
24
+ @Test
25
+ void shouldRegisterAndUnregisterTemplateScheme() {
26
+ PluginTemplatePlugin plugin = new PluginTemplatePlugin(context, schemeManager);
27
+
28
+ plugin.start();
29
+ plugin.stop();
30
+
31
+ verify(schemeManager).register(eq(PluginTemplateRecord.class), any());
32
+ verify(schemeManager).unregister(any());
33
+ }
34
+ }
@@ -0,0 +1,97 @@
1
+ package run.halo.plugintemplate.service.impl;
2
+
3
+ import static org.assertj.core.api.Assertions.assertThat;
4
+ import static org.mockito.Mockito.when;
5
+
6
+ import java.time.Clock;
7
+ import java.time.Instant;
8
+ import java.time.ZoneOffset;
9
+ import org.junit.jupiter.api.Test;
10
+ import org.junit.jupiter.api.extension.ExtendWith;
11
+ import org.mockito.Mock;
12
+ import org.mockito.junit.jupiter.MockitoExtension;
13
+ import reactor.core.publisher.Mono;
14
+ import run.halo.app.plugin.ReactiveSettingFetcher;
15
+ import run.halo.plugintemplate.model.PluginTemplateAudience;
16
+ import run.halo.plugintemplate.setting.PluginTemplateGeneralSetting;
17
+ import run.halo.plugintemplate.setting.PluginTemplateSettingKeys;
18
+ import run.halo.plugintemplate.setting.PluginTemplateUiSetting;
19
+
20
+ @ExtendWith(MockitoExtension.class)
21
+ class PluginTemplateOverviewServiceImplTest {
22
+
23
+ private static final Clock FIXED_CLOCK = Clock.fixed(
24
+ Instant.parse("2026-04-07T10:00:00Z"),
25
+ ZoneOffset.UTC
26
+ );
27
+
28
+ @Mock
29
+ ReactiveSettingFetcher settingFetcher;
30
+
31
+ @Test
32
+ void shouldApplyFetchedSettingsIntoOverview() {
33
+ var generalSetting = new PluginTemplateGeneralSetting();
34
+ generalSetting.setEnableConsoleDashboard(true);
35
+ generalSetting.setEnableUcDashboard(false);
36
+ generalSetting.setEnableAttachmentProvider(false);
37
+
38
+ var uiSetting = new PluginTemplateUiSetting();
39
+ uiSetting.setAccentColor("#102030");
40
+ uiSetting.setDensity("compact");
41
+ uiSetting.setSupportLink("https://example.com/help");
42
+
43
+ when(settingFetcher.fetch(PluginTemplateSettingKeys.GENERAL_GROUP, PluginTemplateGeneralSetting.class))
44
+ .thenReturn(Mono.just(generalSetting));
45
+ when(settingFetcher.fetch(PluginTemplateSettingKeys.UI_GROUP, PluginTemplateUiSetting.class))
46
+ .thenReturn(Mono.just(uiSetting));
47
+
48
+ var service = new PluginTemplateOverviewServiceImpl(FIXED_CLOCK, settingFetcher);
49
+
50
+ var overview = service.getOverview(PluginTemplateAudience.CONSOLE).block();
51
+
52
+ assertThat(overview).isNotNull();
53
+ assertThat(overview.getEnableConsoleDashboard()).isTrue();
54
+ assertThat(overview.getEnableUcDashboard()).isFalse();
55
+ assertThat(overview.getEnableAttachmentProvider()).isFalse();
56
+ assertThat(overview.getAccentColor()).isEqualTo("#102030");
57
+ assertThat(overview.getDensity()).isEqualTo("compact");
58
+ assertThat(overview.getSupportLink()).isEqualTo("https://example.com/help");
59
+ assertThat(overview.getStats())
60
+ .extracting("key", "value")
61
+ .containsExactly(
62
+ org.assertj.core.groups.Tuple.tuple("routes", "1"),
63
+ org.assertj.core.groups.Tuple.tuple("extension-points", "2"),
64
+ org.assertj.core.groups.Tuple.tuple("ui-density", "紧凑")
65
+ );
66
+ assertThat(overview.getFeatures())
67
+ .filteredOn(feature -> "uc-route".equals(feature.getKey()))
68
+ .singleElement()
69
+ .extracting(feature -> feature.getEnabled())
70
+ .isEqualTo(false);
71
+ assertThat(overview.getFeatures())
72
+ .filteredOn(feature -> "attachment-tab".equals(feature.getKey()))
73
+ .singleElement()
74
+ .extracting(feature -> feature.getEnabled())
75
+ .isEqualTo(false);
76
+ }
77
+
78
+ @Test
79
+ void shouldFallbackToDefaultSettingsWhenFetcherReturnsEmpty() {
80
+ when(settingFetcher.fetch(PluginTemplateSettingKeys.GENERAL_GROUP, PluginTemplateGeneralSetting.class))
81
+ .thenReturn(Mono.empty());
82
+ when(settingFetcher.fetch(PluginTemplateSettingKeys.UI_GROUP, PluginTemplateUiSetting.class))
83
+ .thenReturn(Mono.empty());
84
+
85
+ var service = new PluginTemplateOverviewServiceImpl(FIXED_CLOCK, settingFetcher);
86
+
87
+ var overview = service.getOverview(PluginTemplateAudience.UC).block();
88
+
89
+ assertThat(overview).isNotNull();
90
+ assertThat(overview.getEnableConsoleDashboard()).isTrue();
91
+ assertThat(overview.getEnableUcDashboard()).isTrue();
92
+ assertThat(overview.getEnableAttachmentProvider()).isTrue();
93
+ assertThat(overview.getAccentColor()).isEqualTo(PluginTemplateSettingKeys.DEFAULT_ACCENT_COLOR);
94
+ assertThat(overview.getDensity()).isEqualTo(PluginTemplateSettingKeys.DEFAULT_DENSITY);
95
+ assertThat(overview.getSupportLink()).isEqualTo(PluginTemplateSettingKeys.DEFAULT_SUPPORT_LINK);
96
+ }
97
+ }
@@ -0,0 +1,41 @@
1
+ plugins {
2
+ id 'base'
3
+ id "com.github.node-gradle.node" version "7.1.0"
4
+ }
5
+
6
+ group 'run.halo.plugintemplate.ui'
7
+
8
+ tasks.register('pnpmBuild', PnpmTask) {
9
+ group = 'build'
10
+ description = 'Build the UI project using pnpm'
11
+ args = ['build']
12
+ dependsOn tasks.named('pnpmInstall')
13
+ inputs.dir(layout.projectDirectory.dir('src'))
14
+ inputs.files(fileTree(
15
+ dir: layout.projectDirectory,
16
+ includes: ['*.cjs', '*.ts', '*.js', '*.json', '*.yaml']))
17
+ outputs.dir(layout.buildDirectory.dir('dist'))
18
+ }
19
+
20
+ tasks.register('pnpmCheck', PnpmTask) {
21
+ group = 'verification'
22
+ description = 'Run unit tests for the UI project using pnpm'
23
+ args = ['test:unit']
24
+ dependsOn tasks.named('pnpmInstall')
25
+ }
26
+
27
+ tasks.register('pnpmLint', PnpmTask) {
28
+ group = 'verification'
29
+ description = 'Run lint checks for the UI project using pnpm'
30
+ args = ['lint']
31
+ dependsOn tasks.named('pnpmInstall')
32
+ }
33
+
34
+ tasks.named('check') {
35
+ dependsOn tasks.named('pnpmCheck')
36
+ dependsOn tasks.named('pnpmLint')
37
+ }
38
+
39
+ tasks.named('assemble') {
40
+ dependsOn tasks.named('pnpmBuild')
41
+ }
package/ui/env.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ /// <reference types="vite/client" />
2
+ /// <reference types="unplugin-icons/types/vue" />
@@ -0,0 +1,30 @@
1
+ import { globalIgnores } from 'eslint/config'
2
+ import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript'
3
+ import pluginVue from 'eslint-plugin-vue'
4
+ import pluginVitest from '@vitest/eslint-plugin'
5
+ import pluginOxlint from 'eslint-plugin-oxlint'
6
+ import skipFormatting from '@vue/eslint-config-prettier/skip-formatting'
7
+
8
+ // To allow more languages other than `ts` in `.vue` files, uncomment the following lines:
9
+ // import { configureVueProject } from '@vue/eslint-config-typescript'
10
+ // configureVueProject({ scriptLangs: ['ts', 'tsx'] })
11
+ // More info at https://github.com/vuejs/eslint-config-typescript/#advanced-setup
12
+
13
+ export default defineConfigWithVueTs(
14
+ {
15
+ name: 'app/files-to-lint',
16
+ files: ['**/*.{ts,mts,tsx,vue}'],
17
+ },
18
+
19
+ globalIgnores(['**/dist/**', '**/dist-ssr/**', '**/coverage/**', 'src/api/generated/**']),
20
+
21
+ pluginVue.configs['flat/essential'],
22
+ vueTsConfigs.recommended,
23
+
24
+ {
25
+ ...pluginVitest.configs.recommended,
26
+ files: ['src/**/*.spec.ts', 'src/**/*.test.ts'],
27
+ },
28
+ ...pluginOxlint.configs['flat/recommended'],
29
+ skipFormatting,
30
+ )
@@ -0,0 +1,57 @@
1
+ {
2
+ "type": "module",
3
+ "scripts": {
4
+ "build": "run-p type-check \"build-only {@}\" --",
5
+ "build-only": "vite build",
6
+ "dev": "vite build --watch --mode=development",
7
+ "lint:oxlint": "oxlint . --fix -D correctness --ignore-path ../.gitignore",
8
+ "lint:eslint": "eslint . --fix",
9
+ "lint": "run-s lint:*",
10
+ "prettier": "prettier --write src/",
11
+ "test:unit": "vitest --passWithNoTests",
12
+ "type-check": "vue-tsc --build",
13
+ "verify": "run-s lint test:unit type-check"
14
+ },
15
+ "prettier": {
16
+ "printWidth": 100,
17
+ "semi": false,
18
+ "singleQuote": true,
19
+ "tabWidth": 2
20
+ },
21
+ "dependencies": {
22
+ "@halo-dev/api-client": "^2.23.0",
23
+ "@halo-dev/components": "^2.23.0",
24
+ "@halo-dev/ui-shared": "^2.23.0",
25
+ "@element-plus/icons-vue": "^2.3.1",
26
+ "axios": "^1.13.5",
27
+ "element-plus": "^2.10.2",
28
+ "pinia": "^3.0.3",
29
+ "vue": "^3.5.28"
30
+ },
31
+ "devDependencies": {
32
+ "@halo-dev/ui-plugin-bundler-kit": "^2.23.0",
33
+ "@iconify-json/ri": "^1.2.6",
34
+ "@tsconfig/node20": "^20.1.6",
35
+ "@types/jsdom": "^21.1.7",
36
+ "@types/node": "^20.19.1",
37
+ "@vitest/eslint-plugin": "^1.2.7",
38
+ "@vue/eslint-config-prettier": "^10.2.0",
39
+ "@vue/eslint-config-typescript": "^14.5.1",
40
+ "@vue/test-utils": "^2.4.6",
41
+ "@vue/tsconfig": "^0.7.0",
42
+ "eslint": "^9.29.0",
43
+ "eslint-plugin-oxlint": "^0.16.12",
44
+ "eslint-plugin-vue": "~10.0.1",
45
+ "jsdom": "^26.1.0",
46
+ "npm-run-all2": "^7.0.2",
47
+ "oxlint": "^0.16.12",
48
+ "prettier": "^3.6.0",
49
+ "sass": "^1.89.2",
50
+ "typescript": "~5.8.3",
51
+ "unplugin-icons": "^23.0.1",
52
+ "vite": "^8.0.0",
53
+ "vitest": "^4.1.0",
54
+ "vue-tsc": "^3.2.4"
55
+ },
56
+ "packageManager": "pnpm@10.12.4"
57
+ }