mirror of https://github.com/halo-dev/halo
feat: add strategy setting for post slug generation (#4551)
#### What type of PR is this? /kind improvement #### What this PR does / why we need it: 添加文章别名自动生成策略 #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/1790 #### Special notes for your reviewer: 需要后端提供支持在globalInfo里面添加`gSlugMode`字段。它的类型为(后续可能会支持更多的模式) <img width="582" alt="image" src="https://github.com/halo-dev/halo/assets/110895612/586c4742-6172-4bbc-a601-ca04c2a9a281"> #### Does this PR introduce a user-facing change? ```release-note 文章支持多别名生成策略。 ```pull/4587/head
parent
31675dbbba
commit
e13563bad0
|
@ -79,6 +79,7 @@ public class SystemSetting {
|
||||||
Integer categoryPageSize;
|
Integer categoryPageSize;
|
||||||
Integer tagPageSize;
|
Integer tagPageSize;
|
||||||
Boolean review;
|
Boolean review;
|
||||||
|
String slugGenerationStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
|
|
@ -53,6 +53,7 @@ public class GlobalInfoEndpoint {
|
||||||
handleCommentSetting(info, configMap);
|
handleCommentSetting(info, configMap);
|
||||||
handleUserSetting(info, configMap);
|
handleUserSetting(info, configMap);
|
||||||
handleBasicSetting(info, configMap);
|
handleBasicSetting(info, configMap);
|
||||||
|
handlePostSlugGenerationStrategy(info, configMap);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
|
@ -81,6 +82,8 @@ public class GlobalInfoEndpoint {
|
||||||
|
|
||||||
private boolean dataInitialized;
|
private boolean dataInitialized;
|
||||||
|
|
||||||
|
private String postSlugGenerationStrategy;
|
||||||
|
|
||||||
private List<SocialAuthProvider> socialAuthProviders;
|
private List<SocialAuthProvider> socialAuthProviders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,6 +126,13 @@ public class GlobalInfoEndpoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handlePostSlugGenerationStrategy(GlobalInfo info, ConfigMap configMap) {
|
||||||
|
var post = SystemSetting.get(configMap, SystemSetting.Post.GROUP, SystemSetting.Post.class);
|
||||||
|
if (post != null) {
|
||||||
|
info.setPostSlugGenerationStrategy(post.getSlugGenerationStrategy());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void handleBasicSetting(GlobalInfo info, ConfigMap configMap) {
|
private void handleBasicSetting(GlobalInfo info, ConfigMap configMap) {
|
||||||
var basic = SystemSetting.get(configMap, Basic.GROUP, Basic.class);
|
var basic = SystemSetting.get(configMap, Basic.GROUP, Basic.class);
|
||||||
if (basic != null) {
|
if (basic != null) {
|
||||||
|
|
|
@ -31,7 +31,8 @@ data:
|
||||||
"postPageSize": 10,
|
"postPageSize": 10,
|
||||||
"archivePageSize": 10,
|
"archivePageSize": 10,
|
||||||
"categoryPageSize": 10,
|
"categoryPageSize": 10,
|
||||||
"tagPageSize": 10
|
"tagPageSize": 10,
|
||||||
|
"slugGenerationStrategy": "generateByTitle"
|
||||||
}
|
}
|
||||||
comment: |
|
comment: |
|
||||||
{
|
{
|
||||||
|
|
|
@ -55,6 +55,19 @@ spec:
|
||||||
min: 1
|
min: 1
|
||||||
max: 100
|
max: 100
|
||||||
validation: required
|
validation: required
|
||||||
|
- $formkit: select
|
||||||
|
label: "别名生成策略"
|
||||||
|
name: slugGenerationStrategy
|
||||||
|
value: 'generateByTitle'
|
||||||
|
options:
|
||||||
|
- label: '根据标题'
|
||||||
|
value: 'generateByTitle'
|
||||||
|
- label: '时间戳'
|
||||||
|
value: 'timestamp'
|
||||||
|
- label: 'Short UUID'
|
||||||
|
value: 'shortUUID'
|
||||||
|
- label: 'UUID'
|
||||||
|
value: 'UUID'
|
||||||
- group: seo
|
- group: seo
|
||||||
label: SEO 设置
|
label: SEO 设置
|
||||||
formSchema:
|
formSchema:
|
||||||
|
|
|
@ -92,6 +92,7 @@
|
||||||
"pinia": "^2.1.6",
|
"pinia": "^2.1.6",
|
||||||
"pretty-bytes": "^6.0.0",
|
"pretty-bytes": "^6.0.0",
|
||||||
"qs": "^6.11.1",
|
"qs": "^6.11.1",
|
||||||
|
"short-unique-id": "^5.0.2",
|
||||||
"transliteration": "^2.3.5",
|
"transliteration": "^2.3.5",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-demi": "^0.14.5",
|
"vue-demi": "^0.14.5",
|
||||||
|
|
|
@ -182,6 +182,9 @@ importers:
|
||||||
qs:
|
qs:
|
||||||
specifier: ^6.11.1
|
specifier: ^6.11.1
|
||||||
version: 6.11.1
|
version: 6.11.1
|
||||||
|
short-unique-id:
|
||||||
|
specifier: ^5.0.2
|
||||||
|
version: 5.0.2
|
||||||
transliteration:
|
transliteration:
|
||||||
specifier: ^2.3.5
|
specifier: ^2.3.5
|
||||||
version: 2.3.5
|
version: 2.3.5
|
||||||
|
@ -782,6 +785,7 @@ packages:
|
||||||
/@babel/plugin-proposal-async-generator-functions@7.19.1(@babel/core@7.20.12):
|
/@babel/plugin-proposal-async-generator-functions@7.19.1(@babel/core@7.20.12):
|
||||||
resolution: {integrity: sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q==}
|
resolution: {integrity: sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@babel/core': ^7.0.0-0
|
'@babel/core': ^7.0.0-0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -797,6 +801,7 @@ packages:
|
||||||
/@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.20.12):
|
/@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.20.12):
|
||||||
resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==}
|
resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@babel/core': ^7.0.0-0
|
'@babel/core': ^7.0.0-0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -810,6 +815,7 @@ packages:
|
||||||
/@babel/plugin-proposal-class-static-block@7.18.6(@babel/core@7.20.12):
|
/@babel/plugin-proposal-class-static-block@7.18.6(@babel/core@7.20.12):
|
||||||
resolution: {integrity: sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==}
|
resolution: {integrity: sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-static-block instead.
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@babel/core': ^7.12.0
|
'@babel/core': ^7.12.0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -824,6 +830,7 @@ packages:
|
||||||
/@babel/plugin-proposal-dynamic-import@7.18.6(@babel/core@7.20.12):
|
/@babel/plugin-proposal-dynamic-import@7.18.6(@babel/core@7.20.12):
|
||||||
resolution: {integrity: sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==}
|
resolution: {integrity: sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-dynamic-import instead.
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@babel/core': ^7.0.0-0
|
'@babel/core': ^7.0.0-0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -835,6 +842,7 @@ packages:
|
||||||
/@babel/plugin-proposal-export-namespace-from@7.18.9(@babel/core@7.20.12):
|
/@babel/plugin-proposal-export-namespace-from@7.18.9(@babel/core@7.20.12):
|
||||||
resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==}
|
resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-export-namespace-from instead.
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@babel/core': ^7.0.0-0
|
'@babel/core': ^7.0.0-0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -846,6 +854,7 @@ packages:
|
||||||
/@babel/plugin-proposal-json-strings@7.18.6(@babel/core@7.20.12):
|
/@babel/plugin-proposal-json-strings@7.18.6(@babel/core@7.20.12):
|
||||||
resolution: {integrity: sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==}
|
resolution: {integrity: sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-json-strings instead.
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@babel/core': ^7.0.0-0
|
'@babel/core': ^7.0.0-0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -857,6 +866,7 @@ packages:
|
||||||
/@babel/plugin-proposal-logical-assignment-operators@7.18.9(@babel/core@7.20.12):
|
/@babel/plugin-proposal-logical-assignment-operators@7.18.9(@babel/core@7.20.12):
|
||||||
resolution: {integrity: sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==}
|
resolution: {integrity: sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-logical-assignment-operators instead.
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@babel/core': ^7.0.0-0
|
'@babel/core': ^7.0.0-0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -868,6 +878,7 @@ packages:
|
||||||
/@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.20.12):
|
/@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.20.12):
|
||||||
resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==}
|
resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@babel/core': ^7.0.0-0
|
'@babel/core': ^7.0.0-0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -879,6 +890,7 @@ packages:
|
||||||
/@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.20.12):
|
/@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.20.12):
|
||||||
resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==}
|
resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead.
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@babel/core': ^7.0.0-0
|
'@babel/core': ^7.0.0-0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -890,6 +902,7 @@ packages:
|
||||||
/@babel/plugin-proposal-object-rest-spread@7.18.9(@babel/core@7.20.12):
|
/@babel/plugin-proposal-object-rest-spread@7.18.9(@babel/core@7.20.12):
|
||||||
resolution: {integrity: sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q==}
|
resolution: {integrity: sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@babel/core': ^7.0.0-0
|
'@babel/core': ^7.0.0-0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -904,6 +917,7 @@ packages:
|
||||||
/@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.20.12):
|
/@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.20.12):
|
||||||
resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==}
|
resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead.
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@babel/core': ^7.0.0-0
|
'@babel/core': ^7.0.0-0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -915,6 +929,7 @@ packages:
|
||||||
/@babel/plugin-proposal-optional-chaining@7.18.9(@babel/core@7.20.12):
|
/@babel/plugin-proposal-optional-chaining@7.18.9(@babel/core@7.20.12):
|
||||||
resolution: {integrity: sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==}
|
resolution: {integrity: sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@babel/core': ^7.0.0-0
|
'@babel/core': ^7.0.0-0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -927,6 +942,7 @@ packages:
|
||||||
/@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.20.12):
|
/@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.20.12):
|
||||||
resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==}
|
resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead.
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@babel/core': ^7.0.0-0
|
'@babel/core': ^7.0.0-0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -940,6 +956,7 @@ packages:
|
||||||
/@babel/plugin-proposal-private-property-in-object@7.18.6(@babel/core@7.20.12):
|
/@babel/plugin-proposal-private-property-in-object@7.18.6(@babel/core@7.20.12):
|
||||||
resolution: {integrity: sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==}
|
resolution: {integrity: sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-property-in-object instead.
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@babel/core': ^7.0.0-0
|
'@babel/core': ^7.0.0-0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -955,6 +972,7 @@ packages:
|
||||||
/@babel/plugin-proposal-unicode-property-regex@7.18.6(@babel/core@7.20.12):
|
/@babel/plugin-proposal-unicode-property-regex@7.18.6(@babel/core@7.20.12):
|
||||||
resolution: {integrity: sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==}
|
resolution: {integrity: sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-unicode-property-regex instead.
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@babel/core': ^7.0.0-0
|
'@babel/core': ^7.0.0-0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -10168,6 +10186,11 @@ packages:
|
||||||
vscode-textmate: 5.2.0
|
vscode-textmate: 5.2.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/short-unique-id@5.0.2:
|
||||||
|
resolution: {integrity: sha512-4wZq1VLV4hsEx8guP5bN7XnY8UDsVXtdUDWFMP1gvEieAXolq5fWGKpuua21PRXaLn3OybTKFQNm7JGcHSWu/Q==}
|
||||||
|
hasBin: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
/side-channel@1.0.4:
|
/side-channel@1.0.4:
|
||||||
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
|
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
|
@ -1,26 +1,63 @@
|
||||||
import { slugify } from "transliteration";
|
import { slugify } from "transliteration";
|
||||||
import { watch, type Ref } from "vue";
|
import { watch, type Ref } from "vue";
|
||||||
|
import ShortUniqueId from "short-unique-id";
|
||||||
|
import { FormType } from "@/types/slug";
|
||||||
|
import { useGlobalInfoStore } from "@/stores/global-info";
|
||||||
|
import { randomUUID } from "@/utils/id";
|
||||||
|
const uid = new ShortUniqueId();
|
||||||
|
const Strategy = {
|
||||||
|
generateByTitle: (value: string) => {
|
||||||
|
if (!value) return "";
|
||||||
|
return slugify(value, { trim: true });
|
||||||
|
},
|
||||||
|
shortUUID: (value: string) => {
|
||||||
|
if (!value) return "";
|
||||||
|
return uid.randomUUID(8);
|
||||||
|
},
|
||||||
|
UUID: (value: string) => {
|
||||||
|
if (!value) return "";
|
||||||
|
return randomUUID();
|
||||||
|
},
|
||||||
|
timestamp: (value: string) => {
|
||||||
|
if (!value) return "";
|
||||||
|
return new Date().getTime().toString();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const onceList = ["shortUUID", "UUID", "timestamp"];
|
||||||
|
|
||||||
export default function useSlugify(
|
export default function useSlugify(
|
||||||
source: Ref<string>,
|
source: Ref<string>,
|
||||||
target: Ref<string>,
|
target: Ref<string>,
|
||||||
auto: Ref<boolean>
|
auto: Ref<boolean>,
|
||||||
|
formType: FormType
|
||||||
) {
|
) {
|
||||||
watch(
|
watch(
|
||||||
() => source.value,
|
() => source.value,
|
||||||
() => {
|
() => {
|
||||||
if (auto.value) {
|
if (auto.value) {
|
||||||
handleGenerateSlug();
|
handleGenerateSlug(false, formType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleGenerateSlug = () => {
|
const handleGenerateSlug = (forceUpdate = false, formType: FormType) => {
|
||||||
if (!source.value) {
|
const globalInfoStore = useGlobalInfoStore();
|
||||||
|
const mode = globalInfoStore.globalInfo?.postSlugGenerationStrategy;
|
||||||
|
|
||||||
|
if (!mode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
target.value = slugify(source.value, {
|
if (formType != FormType.POST) {
|
||||||
trim: true,
|
target.value = Strategy["generateByTitle"](source.value);
|
||||||
});
|
return;
|
||||||
|
}
|
||||||
|
if (forceUpdate) {
|
||||||
|
target.value = Strategy[mode](source.value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (onceList.includes(mode) && target.value) return;
|
||||||
|
target.value = Strategy[mode](source.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -19,6 +19,7 @@ import AnnotationsForm from "@/components/form/AnnotationsForm.vue";
|
||||||
import useSlugify from "@/composables/use-slugify";
|
import useSlugify from "@/composables/use-slugify";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { usePageUpdateMutate } from "../composables/use-page-update-mutate";
|
import { usePageUpdateMutate } from "../composables/use-page-update-mutate";
|
||||||
|
import { FormType } from "@/types/slug";
|
||||||
|
|
||||||
const initialFormState: SinglePage = {
|
const initialFormState: SinglePage = {
|
||||||
spec: {
|
spec: {
|
||||||
|
@ -277,7 +278,8 @@ const { handleGenerateSlug } = useSlugify(
|
||||||
formState.value.spec.slug = value;
|
formState.value.spec.slug = value;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
computed(() => !isUpdateMode.value)
|
computed(() => !isUpdateMode.value),
|
||||||
|
FormType.SINGLE_PAGE
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -331,7 +333,7 @@ const { handleGenerateSlug } = useSlugify(
|
||||||
$t('core.page.settings.fields.slug.refresh_message')
|
$t('core.page.settings.fields.slug.refresh_message')
|
||||||
"
|
"
|
||||||
class="group flex h-full cursor-pointer items-center border-l px-3 transition-all hover:bg-gray-100"
|
class="group flex h-full cursor-pointer items-center border-l px-3 transition-all hover:bg-gray-100"
|
||||||
@click="handleGenerateSlug"
|
@click="handleGenerateSlug(true, FormType.SINGLE_PAGE)"
|
||||||
>
|
>
|
||||||
<IconRefreshLine
|
<IconRefreshLine
|
||||||
class="h-4 w-4 text-gray-500 group-hover:text-gray-700"
|
class="h-4 w-4 text-gray-500 group-hover:text-gray-700"
|
||||||
|
|
|
@ -24,6 +24,7 @@ import { useThemeCustomTemplates } from "@/modules/interface/themes/composables/
|
||||||
import AnnotationsForm from "@/components/form/AnnotationsForm.vue";
|
import AnnotationsForm from "@/components/form/AnnotationsForm.vue";
|
||||||
import useSlugify from "@/composables/use-slugify";
|
import useSlugify from "@/composables/use-slugify";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { FormType } from "@/types/slug";
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
@ -199,7 +200,8 @@ const { handleGenerateSlug } = useSlugify(
|
||||||
formState.value.spec.slug = value;
|
formState.value.spec.slug = value;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
computed(() => !isUpdateMode.value)
|
computed(() => !isUpdateMode.value),
|
||||||
|
FormType.CATEGORY
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
@ -260,7 +262,7 @@ const { handleGenerateSlug } = useSlugify(
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
class="group flex h-full cursor-pointer items-center border-l px-3 transition-all hover:bg-gray-100"
|
class="group flex h-full cursor-pointer items-center border-l px-3 transition-all hover:bg-gray-100"
|
||||||
@click="handleGenerateSlug"
|
@click="handleGenerateSlug(true, FormType.CATEGORY)"
|
||||||
>
|
>
|
||||||
<IconRefreshLine
|
<IconRefreshLine
|
||||||
class="h-4 w-4 text-gray-500 group-hover:text-gray-700"
|
class="h-4 w-4 text-gray-500 group-hover:text-gray-700"
|
||||||
|
|
|
@ -19,6 +19,7 @@ import { submitForm } from "@formkit/core";
|
||||||
import useSlugify from "@/composables/use-slugify";
|
import useSlugify from "@/composables/use-slugify";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { usePostUpdateMutate } from "../composables/use-post-update-mutate";
|
import { usePostUpdateMutate } from "../composables/use-post-update-mutate";
|
||||||
|
import { FormType } from "@/types/slug";
|
||||||
|
|
||||||
const initialFormState: Post = {
|
const initialFormState: Post = {
|
||||||
spec: {
|
spec: {
|
||||||
|
@ -240,7 +241,8 @@ const { handleGenerateSlug } = useSlugify(
|
||||||
formState.value.spec.slug = value;
|
formState.value.spec.slug = value;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
computed(() => !isUpdateMode.value)
|
computed(() => !isUpdateMode.value),
|
||||||
|
FormType.POST
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
@ -293,7 +295,7 @@ const { handleGenerateSlug } = useSlugify(
|
||||||
$t('core.post.settings.fields.slug.refresh_message')
|
$t('core.post.settings.fields.slug.refresh_message')
|
||||||
"
|
"
|
||||||
class="group flex h-full cursor-pointer items-center border-l px-3 transition-all hover:bg-gray-100"
|
class="group flex h-full cursor-pointer items-center border-l px-3 transition-all hover:bg-gray-100"
|
||||||
@click="handleGenerateSlug"
|
@click="handleGenerateSlug(true, FormType.POST)"
|
||||||
>
|
>
|
||||||
<IconRefreshLine
|
<IconRefreshLine
|
||||||
class="h-4 w-4 text-gray-500 group-hover:text-gray-700"
|
class="h-4 w-4 text-gray-500 group-hover:text-gray-700"
|
||||||
|
|
|
@ -25,6 +25,7 @@ import { setFocus } from "@/formkit/utils/focus";
|
||||||
import AnnotationsForm from "@/components/form/AnnotationsForm.vue";
|
import AnnotationsForm from "@/components/form/AnnotationsForm.vue";
|
||||||
import useSlugify from "@/composables/use-slugify";
|
import useSlugify from "@/composables/use-slugify";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { FormType } from "@/types/slug";
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
@ -158,7 +159,8 @@ const { handleGenerateSlug } = useSlugify(
|
||||||
formState.value.spec.slug = value;
|
formState.value.spec.slug = value;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
computed(() => !isUpdateMode.value)
|
computed(() => !isUpdateMode.value),
|
||||||
|
FormType.TAG
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
@ -220,7 +222,7 @@ const { handleGenerateSlug } = useSlugify(
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
class="group flex h-full cursor-pointer items-center border-l px-3 transition-all hover:bg-gray-100"
|
class="group flex h-full cursor-pointer items-center border-l px-3 transition-all hover:bg-gray-100"
|
||||||
@click="handleGenerateSlug"
|
@click="handleGenerateSlug(true, FormType.TAG)"
|
||||||
>
|
>
|
||||||
<IconRefreshLine
|
<IconRefreshLine
|
||||||
class="h-4 w-4 text-gray-500 group-hover:text-gray-700"
|
class="h-4 w-4 text-gray-500 group-hover:text-gray-700"
|
||||||
|
|
|
@ -12,6 +12,7 @@ import type { ConfigMap, Setting } from "@halo-dev/api-client";
|
||||||
import { useQuery, useQueryClient } from "@tanstack/vue-query";
|
import { useQuery, useQueryClient } from "@tanstack/vue-query";
|
||||||
import { apiClient } from "@/utils/api-client";
|
import { apiClient } from "@/utils/api-client";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useGlobalInfoStore } from "@/stores/global-info";
|
||||||
|
|
||||||
const SYSTEM_CONFIGMAP_NAME = "system";
|
const SYSTEM_CONFIGMAP_NAME = "system";
|
||||||
|
|
||||||
|
@ -58,7 +59,7 @@ const handleSaveConfigMap = async () => {
|
||||||
Toast.success(t("core.common.toast.save_success"));
|
Toast.success(t("core.common.toast.save_success"));
|
||||||
|
|
||||||
queryClient.invalidateQueries({ queryKey: ["system-configMap"] });
|
queryClient.invalidateQueries({ queryKey: ["system-configMap"] });
|
||||||
|
await useGlobalInfoStore().fetchGlobalInfo();
|
||||||
systemConfigMapStore.configMap = data;
|
systemConfigMapStore.configMap = data;
|
||||||
|
|
||||||
saving.value = false;
|
saving.value = false;
|
||||||
|
|
|
@ -30,7 +30,6 @@ export async function setupPluginModules(app: App) {
|
||||||
|
|
||||||
enabledPluginNames.forEach((name) => {
|
enabledPluginNames.forEach((name) => {
|
||||||
const module = window[name];
|
const module = window[name];
|
||||||
|
|
||||||
if (module) {
|
if (module) {
|
||||||
registerModule(app, module, false);
|
registerModule(app, module, false);
|
||||||
pluginModuleStore.registerPluginModule(name, module);
|
pluginModuleStore.registerPluginModule(name, module);
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import type { ModeType } from "./slug";
|
||||||
|
|
||||||
export interface GlobalInfo {
|
export interface GlobalInfo {
|
||||||
externalUrl: string;
|
externalUrl: string;
|
||||||
timeZone: string;
|
timeZone: string;
|
||||||
|
@ -10,6 +12,7 @@ export interface GlobalInfo {
|
||||||
userInitialized: boolean;
|
userInitialized: boolean;
|
||||||
dataInitialized: boolean;
|
dataInitialized: boolean;
|
||||||
favicon?: string;
|
favicon?: string;
|
||||||
|
postSlugGenerationStrategy: ModeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Info {
|
export interface Info {
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
export type ModeType = "UUID" | "shortUUID" | "timestamp" | "generateByTitle";
|
||||||
|
export enum FormType {
|
||||||
|
TAG = "Tag",
|
||||||
|
CATEGORY = "Category",
|
||||||
|
POST = "Post",
|
||||||
|
SINGLE_PAGE = "SinglePage",
|
||||||
|
}
|
Loading…
Reference in New Issue