mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-03-28 17:42:40 +01:00
Compare commits
38 Commits
copilot-in
...
v10.3.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d607bdb5b | ||
|
|
823d99aff2 | ||
|
|
9005a94355 | ||
|
|
dff2fb0149 | ||
|
|
7d3653589b | ||
|
|
31460026ee | ||
|
|
1a97a11c1c | ||
|
|
430760eca8 | ||
|
|
800acde914 | ||
|
|
06ff07bec8 | ||
|
|
27a4d9bc71 | ||
|
|
45f2794631 | ||
|
|
42f6557bd6 | ||
|
|
78d42ac09b | ||
|
|
73e00a7a94 | ||
|
|
36e0ef0171 | ||
|
|
380bc804fd | ||
|
|
458aadcbef | ||
|
|
adb541805a | ||
|
|
e7ca5488de | ||
|
|
f583e0e91a | ||
|
|
00bbb3879f | ||
|
|
1d7436d051 | ||
|
|
86de4fa767 | ||
|
|
ced7e41fe6 | ||
|
|
b81e92ef9e | ||
|
|
ec3c1eec58 | ||
|
|
c173fe973c | ||
|
|
47e8caeede | ||
|
|
5b3223abb6 | ||
|
|
2cb6c89d87 | ||
|
|
4197de2b2e | ||
|
|
fe7a296cc1 | ||
|
|
b03d972d31 | ||
|
|
0e6e776f70 | ||
|
|
bd1fc32f1c | ||
|
|
38d48b9fa7 | ||
|
|
c92a5cac00 |
2
.github/workflows/release-beta.yml
vendored
2
.github/workflows/release-beta.yml
vendored
@@ -2,7 +2,7 @@ name: BETA Release
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- beta
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
|
||||
18
CHANGELOG.md
18
CHANGELOG.md
@@ -1,16 +1,32 @@
|
||||
# Change Log
|
||||
|
||||
## [10.3.0] - 2024-xx-xx
|
||||
## [10.3.0] - 2024-08-13 - [Release notes](https://beta.frontmatter.codes/updates/v10.3.0)
|
||||
|
||||
### ✨ New features
|
||||
|
||||
- [#823](https://github.com/estruyf/vscode-front-matter/issues/823): Integrated GitHub Copilot support for titles, descriptions, and taxonomy field suggestions
|
||||
- [#824](https://github.com/estruyf/vscode-front-matter/issues/824): Added the ability to link custom actions to fields
|
||||
|
||||
### 🎨 Enhancements
|
||||
|
||||
- [#467](https://github.com/estruyf/vscode-front-matter/issues/467): New `fmContentType` metadata field to link content type (fallback to the `type` field)
|
||||
- [#819](https://github.com/estruyf/vscode-front-matter/issues/819): Added new extensibility support for media scripts
|
||||
- [#820](https://github.com/estruyf/vscode-front-matter/issues/820): Moving the website and API to different hosts
|
||||
- [#821](https://github.com/estruyf/vscode-front-matter/issues/821): Added URI handler to support command links from the documentation
|
||||
- [#822](https://github.com/estruyf/vscode-front-matter/issues/822): Added docs to the panel & dashboard views
|
||||
- [#829](https://github.com/estruyf/vscode-front-matter/issues/829): UI extensibility is now generally available
|
||||
- [#831](https://github.com/estruyf/vscode-front-matter/issues/831): Added "select all" action bar button to the content and media dashboards
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
- [#827](https://github.com/estruyf/vscode-front-matter/issues/827): Fix for `frontmatter.json` file which gets created when already present in a sub-folder
|
||||
- [#830](https://github.com/estruyf/vscode-front-matter/issues/830): Fix for using the SEO title field setting to change the title field reference
|
||||
- [#832](https://github.com/estruyf/vscode-front-matter/issues/832): Fix for finding folders with wildcards in the path
|
||||
|
||||
## [10.2.1] - 2024-08-08
|
||||
|
||||
- [#820](https://github.com/estruyf/vscode-front-matter/issues/820): Update API links to the new API URL
|
||||
|
||||
## [10.2.0] - 2024-06-12 - [Release notes](https://beta.frontmatter.codes/updates/v10.2.0)
|
||||
|
||||
### ✨ New features
|
||||
|
||||
@@ -203,18 +203,7 @@ You can open showcase issues for the following things:
|
||||
|
||||
## 📊 Telemetry
|
||||
|
||||
The Front Matter CMS extension collects telemetry data to help us build a better understand which features from the CMS are used. The extension respects the `telemetry.enableTelemetry` setting which you can learn more about in the [Visual Studio Code FAQ](https://aka.ms/vscode-remote/telemetry), or you can only disable it for the extension by configuring the `frontMatter.telemetry.disable` setting.
|
||||
|
||||
We only collect the following data:
|
||||
|
||||
- Type of event
|
||||
- Extension title (main or beta)
|
||||
- Extension version
|
||||
|
||||
No user-specific data is collected, you can check the telemetry implementation in the following files:
|
||||
|
||||
- [Telemetry class](https://github.com/estruyf/vscode-front-matter/blob/59528a3db01be8d34dc40638e6cf827090e31986/src/helpers/Telemetry.ts)
|
||||
- [Metrics API](https://github.com/FrontMatter/web-documentation-nextjs/blob/main/pages/api/metrics.ts)
|
||||
The Front Matter CMS extension only uses telemetry on application crashes. The extension respects the `telemetry.enableTelemetry` setting which you can learn more about in the [Visual Studio Code FAQ](https://aka.ms/vscode-remote/telemetry).
|
||||
|
||||
For crash reports in the webviews, we make use of Sentry to help us understand what went wrong. This data is only used to fix issues and improve the extension. You can find more information about the Sentry implementation in the following files:
|
||||
|
||||
|
||||
13
README.md
13
README.md
@@ -209,18 +209,7 @@ You can open showcase issues for the following things:
|
||||
|
||||
## 📊 Telemetry
|
||||
|
||||
The Front Matter CMS extension collects telemetry data to help us build a better understand which features from the CMS are used. The extension respects the `telemetry.enableTelemetry` setting which you can learn more about in the [Visual Studio Code FAQ](https://aka.ms/vscode-remote/telemetry), or you can only disable it for the extension by configuring the `frontMatter.telemetry.disable` setting.
|
||||
|
||||
We only collect the following data:
|
||||
|
||||
- Type of event
|
||||
- Extension title (main or beta)
|
||||
- Extension version
|
||||
|
||||
No user-specific data is collected, you can check the telemetry implementation in the following files:
|
||||
|
||||
- [Telemetry class](https://github.com/estruyf/vscode-front-matter/blob/59528a3db01be8d34dc40638e6cf827090e31986/src/helpers/Telemetry.ts)
|
||||
- [Metrics API](https://github.com/FrontMatter/web-documentation-nextjs/blob/main/pages/api/metrics.ts)
|
||||
The Front Matter CMS extension only uses telemetry on application crashes. The extension respects the `telemetry.enableTelemetry` setting which you can learn more about in the [Visual Studio Code FAQ](https://aka.ms/vscode-remote/telemetry).
|
||||
|
||||
For crash reports in the webviews, we make use of Sentry to help us understand what went wrong. This data is only used to fix issues and improve the extension. You can find more information about the Sentry implementation in the following files:
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 3.3 KiB |
@@ -1,45 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 28 28" style="enable-background:new 0 0 28 28;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFE45E;}
|
||||
.st1{fill:none;stroke:#FFE45E;stroke-width:2;stroke-miterlimit:10;}
|
||||
.st2{font-family:'MyriadPro-Bold';}
|
||||
.st3{font-size:8px;}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M4.1,10.2H2.4V2.1h3.1V4H4.1v1.2h1.2V7H4.1V10.2z"/>
|
||||
<path class="st0" d="M10.7,10.2H8.9L8,7.3c0-0.1,0-0.1,0-0.2C7.9,7.1,7.9,7,7.8,6.8v0.6v2.9H6.1V2.1h1.8c0.8,0,1.3,0.2,1.8,0.6
|
||||
c0.5,0.5,0.8,1.2,0.8,2.1c0,1-0.4,1.6-1.1,2L10.7,10.2z M7.9,5.8L7.9,5.8c0.3,0,0.5-0.1,0.6-0.3S8.7,5,8.7,4.8c0-0.6-0.3-1-0.8-1
|
||||
l0,0V5.8z"/>
|
||||
<path class="st0" d="M16.1,6.2c0,1.2-0.2,2.3-0.7,3.1s-1.1,1.2-1.7,1.2s-1.2-0.3-1.6-0.9c-0.6-0.8-0.9-1.9-0.9-3.4
|
||||
s0.3-2.6,0.9-3.4C12.6,2.3,13,2,13.7,2c0.8,0,1.3,0.4,1.8,1.2C15.8,3.8,16.1,4.8,16.1,6.2z M14.3,6.2c0-1.4-0.2-2.2-0.7-2.2
|
||||
c-0.2,0-0.4,0.2-0.5,0.6c-0.1,0.4-0.2,0.9-0.2,1.6c0,0.7,0.1,1.2,0.2,1.6c0.1,0.4,0.3,0.6,0.5,0.6c0.2,0,0.4-0.2,0.5-0.6
|
||||
C14.2,7.3,14.3,6.9,14.3,6.2z"/>
|
||||
<path class="st0" d="M16.8,10.2V2.1h1.7l0.9,2.9c0.1,0.1,0.1,0.3,0.2,0.6c0.1,0.2,0.1,0.5,0.2,0.8L20,7c-0.1-0.7-0.1-1.3-0.2-1.8
|
||||
s-0.1-1-0.1-1.2V2.1h1.7v8.2h-1.6l-0.9-3c-0.1-0.3-0.2-0.6-0.3-0.9c-0.1-0.3-0.1-0.6-0.2-0.8c0,0.6,0.1,1.1,0.1,1.5
|
||||
c0,0.4,0,0.8,0,1.2v2.1h-1.7V10.2z"/>
|
||||
<path class="st0" d="M24.6,10.2h-1.7V4h-1V2.1h3.7V4h-1.1V10.2z"/>
|
||||
</g>
|
||||
</g>
|
||||
<rect class="st1" width="28" height="28"/>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M3.1,11.6H4l0.6,3c0.1,0.4,0.2,0.8,0.2,1.2C4.9,16.2,4.9,16.6,5,17c0-0.1,0-0.1,0-0.1v-0.1l0.2-0.9l0.1-0.8
|
||||
l0.1-0.5l0.6-3h0.9l0.7,7.5h-1l-0.2-2.6c0-0.1,0-0.2,0-0.3c0-0.1,0-0.2,0-0.2v-1v-0.9l0,0c0,0,0,0,0-0.1v0.2c0,0.2,0,0.3-0.1,0.5
|
||||
c-0.1,0.2,0,0.2-0.1,0.3L6,15.7V16l-0.6,3.3H4.7l-0.6-2.8c-0.1-0.4-0.2-0.8-0.2-1.1c-0.1-0.4-0.1-0.8-0.2-1.2l-0.3,5.2h-1
|
||||
L3.1,11.6z"/>
|
||||
<path class="st0" d="M9.4,11.6h0.8l1.6,7.5h-1l-0.3-1.5H9l-0.3,1.5h-1L9.4,11.6z M10.4,16.8l-0.3-1.2C10,14.8,9.8,13.9,9.7,13
|
||||
c0,0.5-0.1,0.9-0.2,1.4c-0.1,0.5-0.2,1-0.3,1.5l-0.2,1L10.4,16.8L10.4,16.8z"/>
|
||||
<path class="st0" d="M11.6,11.6h3.3v0.9h-1.1v6.7h-1v-6.7h-1.2V11.6z"/>
|
||||
<path class="st0" d="M14.9,11.6h3.3v0.9h-1.1v6.7h-1v-6.7h-1.2V11.6z"/>
|
||||
<path class="st0" d="M18.8,11.6h2.7v0.9h-1.7v2.4h1.5v0.9h-1.5v2.6h1.7v0.9h-2.7V11.6z"/>
|
||||
<path class="st0" d="M22.3,11.6h1.3c0.6,0,1,0.1,1.2,0.4c0.3,0.3,0.5,0.9,0.5,1.6c0,0.5-0.1,1-0.3,1.3c-0.2,0.3-0.4,0.5-0.8,0.6
|
||||
l1.4,3.7h-1l-1.4-3.7v3.7h-1L22.3,11.6L22.3,11.6z M23.3,14.9c0.4,0,0.7-0.1,0.8-0.3c0.2-0.2,0.2-0.5,0.2-0.9c0-0.2,0-0.4-0.1-0.6
|
||||
c-0.1-0.2-0.1-0.3-0.2-0.4c-0.1-0.1-0.2-0.2-0.3-0.2s-0.3-0.1-0.4-0.1h-0.2v2.5H23.3z"/>
|
||||
</g>
|
||||
</g>
|
||||
<text transform="matrix(1 0 0 1 5.4457 25.9479)" class="st0 st2 st3">BETA</text>
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 28 28">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
stroke-width: 0px;
|
||||
}
|
||||
|
||||
.cls-1, .cls-2, .cls-3, .cls-4 {
|
||||
fill: #c91980;
|
||||
}
|
||||
|
||||
.cls-2 {
|
||||
font-family: Futura-MediumItalic, Futura;
|
||||
font-size: 8px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.cls-2, .cls-3, .cls-4, .cls-5 {
|
||||
isolation: isolate;
|
||||
}
|
||||
|
||||
.cls-2, .cls-4 {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.cls-3 {
|
||||
font-family: Futura-CondensedExtraBold, Futura;
|
||||
font-size: 10.6px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.cls-4 {
|
||||
font-family: Futura-CondensedMedium, Futura;
|
||||
font-size: 10.1px;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<g class="cls-5">
|
||||
<text class="cls-4" transform="translate(2.1 18.9) scale(1 1)"><tspan x="0" y="0">MATTER</tspan></text>
|
||||
</g>
|
||||
<g class="cls-5">
|
||||
<text class="cls-2" transform="translate(1.9 26)"><tspan x="0" y="0">BETA</tspan></text>
|
||||
</g>
|
||||
<rect class="cls-1" x="2.4" width="3" height="1"/>
|
||||
<rect class="cls-1" x="6.9" width="3" height="1"/>
|
||||
<rect class="cls-1" x="11.4" width="3" height="1"/>
|
||||
<rect class="cls-1" x="2.4" y="27" width="3" height="1"/>
|
||||
<rect class="cls-1" x="6.9" y="27" width="3" height="1"/>
|
||||
<rect class="cls-1" x="11.4" y="27" width="3" height="1"/>
|
||||
<g class="cls-5">
|
||||
<text class="cls-3" transform="translate(2.1 10.1) scale(.8 1)"><tspan x="0" y="0">FRONT</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -154,6 +154,7 @@
|
||||
"dashboard.filters.languageFilter.all": "All",
|
||||
|
||||
"dashboard.header.actionsBar.itemsSelected": "{0} selected",
|
||||
"dashboard.header.actionsBar.selectAll": "Select all",
|
||||
"dashboard.header.actionsBar.alertDelete.title": "Delete selected files",
|
||||
"dashboard.header.actionsBar.alertDelete.description": "Are you sure you want to delete the selected files?",
|
||||
|
||||
@@ -438,6 +439,9 @@
|
||||
|
||||
"panel.fields.wrapperField.unknown": "Unkown field type: {0}",
|
||||
|
||||
"panel.fields.fieldCustomAction.button.title": "Custom action",
|
||||
"panel.fields.fieldCustomAction.executing": "Executing field action...",
|
||||
|
||||
"panel.actions.title": "Actions",
|
||||
|
||||
"panel.articleDetails.title": "More details",
|
||||
|
||||
138
package-lock.json
generated
138
package-lock.json
generated
@@ -2935,8 +2935,7 @@
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.17.tgz",
|
||||
"integrity": "sha512-/cpVNRLSfhOtcGflT13P2794gVSgmPgTR+erw5ifnMLZb0UnSlkK4tquLmkd3BhA+nLo5tX8Cu0upUsGKvKbmg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
@@ -3116,8 +3115,7 @@
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz",
|
||||
"integrity": "sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/browserslist"
|
||||
},
|
||||
@@ -3211,8 +3209,7 @@
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001583.tgz",
|
||||
"integrity": "sha512-acWTYaha8xfhA/Du/z4sNZjHUWjkiuoAi2LM+T/aL+kemKQgPT1xBb/YKjlQ0Qo8gvbHsGNplrEJ+9G3gL7i4Q==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/browserslist"
|
||||
},
|
||||
@@ -3325,12 +3322,10 @@
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
],
|
||||
"funding": [{
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}],
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
@@ -3988,12 +3983,10 @@
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
|
||||
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
]
|
||||
"funding": [{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}]
|
||||
},
|
||||
"node_modules/domhandler": {
|
||||
"version": "5.0.3",
|
||||
@@ -4854,12 +4847,10 @@
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
|
||||
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"funding": [{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}],
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
@@ -5462,8 +5453,7 @@
|
||||
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz",
|
||||
"integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/mdevils"
|
||||
},
|
||||
@@ -6038,8 +6028,7 @@
|
||||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
|
||||
"integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
@@ -7086,8 +7075,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz",
|
||||
"integrity": "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7121,8 +7109,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz",
|
||||
"integrity": "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7276,8 +7263,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz",
|
||||
"integrity": "sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7297,8 +7283,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz",
|
||||
"integrity": "sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7319,8 +7304,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz",
|
||||
"integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7339,8 +7323,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz",
|
||||
"integrity": "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7361,8 +7344,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz",
|
||||
"integrity": "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7383,8 +7365,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz",
|
||||
"integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7403,8 +7384,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz",
|
||||
"integrity": "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7422,8 +7402,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz",
|
||||
"integrity": "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7443,8 +7422,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz",
|
||||
"integrity": "sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7463,8 +7441,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz",
|
||||
"integrity": "sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7482,8 +7459,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz",
|
||||
"integrity": "sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7504,8 +7480,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz",
|
||||
"integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7520,8 +7495,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz",
|
||||
"integrity": "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7536,8 +7510,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz",
|
||||
"integrity": "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7555,8 +7528,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz",
|
||||
"integrity": "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7574,8 +7546,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz",
|
||||
"integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7595,8 +7566,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz",
|
||||
"integrity": "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7617,8 +7587,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz",
|
||||
"integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7633,8 +7602,7 @@
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz",
|
||||
"integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
@@ -7816,12 +7784,10 @@
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"funding": [{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}],
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
@@ -8699,8 +8665,7 @@
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz",
|
||||
"integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
@@ -8763,8 +8728,7 @@
|
||||
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
|
||||
"integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
@@ -9121,8 +9085,7 @@
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
@@ -10585,8 +10548,7 @@
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
@@ -10644,8 +10606,7 @@
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
@@ -12184,8 +12145,7 @@
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
|
||||
"integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"funding": [{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/browserslist"
|
||||
},
|
||||
@@ -13052,4 +13012,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
374
package.json
374
package.json
@@ -10,8 +10,7 @@
|
||||
"color": "#0e131f",
|
||||
"theme": "dark"
|
||||
},
|
||||
"badges": [
|
||||
{
|
||||
"badges": [{
|
||||
"description": "version",
|
||||
"url": "https://img.shields.io/github/package-json/v/estruyf/vscode-front-matter?color=green&label=vscode-front-matter&style=flat-square",
|
||||
"href": "https://github.com/estruyf/vscode-front-matter"
|
||||
@@ -71,8 +70,7 @@
|
||||
"**/.frontmatter/config/*.json": "jsonc"
|
||||
}
|
||||
},
|
||||
"keybindings": [
|
||||
{
|
||||
"keybindings": [{
|
||||
"command": "frontMatter.dashboard",
|
||||
"key": "alt+d"
|
||||
},
|
||||
@@ -96,23 +94,19 @@
|
||||
}
|
||||
],
|
||||
"viewsContainers": {
|
||||
"activitybar": [
|
||||
{
|
||||
"id": "frontmatter-explorer",
|
||||
"title": "FM",
|
||||
"icon": "$(fm-logo)"
|
||||
}
|
||||
]
|
||||
"activitybar": [{
|
||||
"id": "frontmatter-explorer",
|
||||
"title": "FM",
|
||||
"icon": "$(fm-logo)"
|
||||
}]
|
||||
},
|
||||
"views": {
|
||||
"frontmatter-explorer": [
|
||||
{
|
||||
"id": "frontMatter.explorer",
|
||||
"name": "Front Matter",
|
||||
"icon": "$(fm-logo)",
|
||||
"type": "webview"
|
||||
}
|
||||
]
|
||||
"frontmatter-explorer": [{
|
||||
"id": "frontMatter.explorer",
|
||||
"name": "Front Matter",
|
||||
"icon": "$(fm-logo)",
|
||||
"type": "webview"
|
||||
}]
|
||||
},
|
||||
"configuration": {
|
||||
"title": "%settings.configuration.title%",
|
||||
@@ -180,8 +174,7 @@
|
||||
"frontMatter.content.defaultFileType": {
|
||||
"type": "string",
|
||||
"default": "md",
|
||||
"oneOf": [
|
||||
{
|
||||
"oneOf": [{
|
||||
"enum": [
|
||||
"md",
|
||||
"mdx"
|
||||
@@ -197,8 +190,7 @@
|
||||
"frontMatter.content.defaultSorting": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"oneOf": [
|
||||
{
|
||||
"oneOf": [{
|
||||
"enum": [
|
||||
"LastModifiedAsc",
|
||||
"LastModifiedDesc",
|
||||
@@ -550,8 +542,7 @@
|
||||
"categories"
|
||||
],
|
||||
"markdownDescription": "%setting.frontMatter.content.filters.markdownDescription%",
|
||||
"items": [
|
||||
{
|
||||
"items": [{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"contentFolders",
|
||||
@@ -577,6 +568,7 @@
|
||||
"default": [],
|
||||
"markdownDescription": "%setting.frontMatter.custom.scripts.markdownDescription%",
|
||||
"items": {
|
||||
"$id": "#customscript",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
@@ -624,8 +616,7 @@
|
||||
"command": {
|
||||
"$id": "#scriptCommand",
|
||||
"type": "string",
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [{
|
||||
"enum": [
|
||||
"node",
|
||||
"bash",
|
||||
@@ -821,8 +812,7 @@
|
||||
"title",
|
||||
"file"
|
||||
],
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [{
|
||||
"required": [
|
||||
"schema"
|
||||
]
|
||||
@@ -876,8 +866,7 @@
|
||||
"id",
|
||||
"path"
|
||||
],
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [{
|
||||
"required": [
|
||||
"schema"
|
||||
]
|
||||
@@ -1118,29 +1107,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": [
|
||||
{
|
||||
"name": "default",
|
||||
"fileTypes": null,
|
||||
"fields": [
|
||||
{
|
||||
"title": "Title",
|
||||
"name": "title",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"title": "Caption",
|
||||
"name": "caption",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"title": "Alt text",
|
||||
"name": "alt",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"default": [{
|
||||
"name": "default",
|
||||
"fileTypes": null,
|
||||
"fields": [{
|
||||
"title": "Title",
|
||||
"name": "title",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"title": "Caption",
|
||||
"name": "caption",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"title": "Alt text",
|
||||
"name": "alt",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}],
|
||||
"scope": "Media"
|
||||
},
|
||||
"frontMatter.media.supportedMimeTypes": {
|
||||
@@ -1243,9 +1229,15 @@
|
||||
"fileType": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"enum": [
|
||||
"md",
|
||||
"mdx"
|
||||
"oneOf": [{
|
||||
"enum": [
|
||||
"md",
|
||||
"mdx"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"description": "%setting.frontMatter.taxonomy.contentTypes.items.properties.fileType.description%"
|
||||
},
|
||||
@@ -1376,8 +1368,7 @@
|
||||
"default": "",
|
||||
"description": "%setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.taxonomyId.description%",
|
||||
"not": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [{
|
||||
"const": ""
|
||||
},
|
||||
{
|
||||
@@ -1564,6 +1555,13 @@
|
||||
"description": "%setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.when.properties.caseSensitive.description%"
|
||||
}
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"type": "array",
|
||||
"description": "%setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.actions.description%",
|
||||
"items": {
|
||||
"$ref": "#customscript"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@@ -1571,8 +1569,7 @@
|
||||
"type",
|
||||
"name"
|
||||
],
|
||||
"allOf": [
|
||||
{
|
||||
"allOf": [{
|
||||
"if": {
|
||||
"properties": {
|
||||
"type": {
|
||||
@@ -1784,51 +1781,48 @@
|
||||
"fields"
|
||||
]
|
||||
},
|
||||
"default": [
|
||||
{
|
||||
"name": "default",
|
||||
"pageBundle": false,
|
||||
"fields": [
|
||||
{
|
||||
"title": "Title",
|
||||
"name": "title",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"title": "Description",
|
||||
"name": "description",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"title": "Publishing date",
|
||||
"name": "date",
|
||||
"type": "datetime",
|
||||
"default": "{{now}}",
|
||||
"isPublishDate": true
|
||||
},
|
||||
{
|
||||
"title": "Content preview",
|
||||
"name": "preview",
|
||||
"type": "image"
|
||||
},
|
||||
{
|
||||
"title": "Is in draft",
|
||||
"name": "draft",
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"title": "Tags",
|
||||
"name": "tags",
|
||||
"type": "tags"
|
||||
},
|
||||
{
|
||||
"title": "Categories",
|
||||
"name": "categories",
|
||||
"type": "categories"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"default": [{
|
||||
"name": "default",
|
||||
"pageBundle": false,
|
||||
"fields": [{
|
||||
"title": "Title",
|
||||
"name": "title",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"title": "Description",
|
||||
"name": "description",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"title": "Publishing date",
|
||||
"name": "date",
|
||||
"type": "datetime",
|
||||
"default": "{{now}}",
|
||||
"isPublishDate": true
|
||||
},
|
||||
{
|
||||
"title": "Content preview",
|
||||
"name": "preview",
|
||||
"type": "image"
|
||||
},
|
||||
{
|
||||
"title": "Is in draft",
|
||||
"name": "draft",
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"title": "Tags",
|
||||
"name": "tags",
|
||||
"type": "tags"
|
||||
},
|
||||
{
|
||||
"title": "Categories",
|
||||
"name": "categories",
|
||||
"type": "categories"
|
||||
}
|
||||
]
|
||||
}],
|
||||
"scope": "Taxonomy"
|
||||
},
|
||||
"frontMatter.taxonomy.customTaxonomy": {
|
||||
@@ -1841,8 +1835,7 @@
|
||||
"type": "string",
|
||||
"description": "%setting.frontMatter.taxonomy.customTaxonomy.items.properties.id.description%",
|
||||
"not": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [{
|
||||
"const": ""
|
||||
},
|
||||
{
|
||||
@@ -1998,11 +1991,6 @@
|
||||
},
|
||||
"scope": "Taxonomy"
|
||||
},
|
||||
"frontMatter.telemetry.disable": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"markdownDescription": "%setting.frontMatter.telemetry.disable.markdownDescription%"
|
||||
},
|
||||
"frontMatter.templates.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
@@ -2034,11 +2022,15 @@
|
||||
"info",
|
||||
"verbose"
|
||||
]
|
||||
},
|
||||
"frontMatter.copilot.family": {
|
||||
"type": "string",
|
||||
"default": "gpt-3.5-turbo",
|
||||
"markdownDescription": "%setting.frontMatter.copilot.family.markdownDescription%"
|
||||
}
|
||||
}
|
||||
},
|
||||
"commands": [
|
||||
{
|
||||
"commands": [{
|
||||
"command": "frontMatter.project.switch",
|
||||
"title": "%command.frontMatter.project.switch%",
|
||||
"category": "Front Matter",
|
||||
@@ -2370,21 +2362,16 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"submenus": [
|
||||
{
|
||||
"id": "frontmatter.submenu",
|
||||
"label": "Front Matter"
|
||||
}
|
||||
],
|
||||
"submenus": [{
|
||||
"id": "frontmatter.submenu",
|
||||
"label": "Front Matter"
|
||||
}],
|
||||
"menus": {
|
||||
"webview/context": [
|
||||
{
|
||||
"command": "workbench.action.webview.openDeveloperTools",
|
||||
"when": "frontMatter:isDevelopment"
|
||||
}
|
||||
],
|
||||
"editor/title": [
|
||||
{
|
||||
"webview/context": [{
|
||||
"command": "workbench.action.webview.openDeveloperTools",
|
||||
"when": "frontMatter:isDevelopment"
|
||||
}],
|
||||
"editor/title": [{
|
||||
"command": "frontMatter.markup.heading",
|
||||
"group": "navigation@-133",
|
||||
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg"
|
||||
@@ -2470,14 +2457,11 @@
|
||||
"when": "resourceFilename == 'frontmatter.json'"
|
||||
}
|
||||
],
|
||||
"explorer/context": [
|
||||
{
|
||||
"submenu": "frontmatter.submenu",
|
||||
"group": "frontmatter@1"
|
||||
}
|
||||
],
|
||||
"frontmatter.submenu": [
|
||||
{
|
||||
"explorer/context": [{
|
||||
"submenu": "frontmatter.submenu",
|
||||
"group": "frontmatter@1"
|
||||
}],
|
||||
"frontmatter.submenu": [{
|
||||
"command": "frontMatter.createFromTemplate",
|
||||
"when": "explorerResourceIsFolder",
|
||||
"group": "frontmatter@1"
|
||||
@@ -2493,8 +2477,7 @@
|
||||
"group": "frontmatter@3"
|
||||
}
|
||||
],
|
||||
"commandPalette": [
|
||||
{
|
||||
"commandPalette": [{
|
||||
"command": "frontMatter.init",
|
||||
"when": "frontMatterCanInit"
|
||||
},
|
||||
@@ -2671,8 +2654,7 @@
|
||||
"when": "frontMatter:file:isValid == true"
|
||||
}
|
||||
],
|
||||
"view/title": [
|
||||
{
|
||||
"view/title": [{
|
||||
"command": "frontMatter.docs",
|
||||
"group": "navigation@-1",
|
||||
"when": "view == frontMatter.explorer"
|
||||
@@ -2682,23 +2664,23 @@
|
||||
"group": "navigation@0",
|
||||
"when": "view == frontMatter.explorer"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.collapseSections",
|
||||
"group": "navigation@1",
|
||||
"when": "view == frontMatter.explorer"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.mode.switch",
|
||||
"group": "navigation@2",
|
||||
"group": "navigation@1",
|
||||
"when": "view == frontMatter.explorer && frontMatter:has:modes == true"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.project.switch",
|
||||
"group": "navigation@3",
|
||||
"group": "navigation@2",
|
||||
"when": "view == frontMatter.explorer && frontMatter:project:switch:enabled"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.settings.refresh",
|
||||
"group": "navigation@3",
|
||||
"when": "view == frontMatter.explorer"
|
||||
},
|
||||
{
|
||||
"command": "frontMatter.collapseSections",
|
||||
"group": "navigation@4",
|
||||
"when": "view == frontMatter.explorer"
|
||||
},
|
||||
@@ -2709,16 +2691,13 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"languages": [
|
||||
{
|
||||
"id": "frontmatter.project.output",
|
||||
"mimetypes": [
|
||||
"text/x-code-output"
|
||||
]
|
||||
}
|
||||
],
|
||||
"grammars": [
|
||||
{
|
||||
"languages": [{
|
||||
"id": "frontmatter.project.output",
|
||||
"mimetypes": [
|
||||
"text/x-code-output"
|
||||
]
|
||||
}],
|
||||
"grammars": [{
|
||||
"path": "./syntaxes/hugo.tmLanguage.json",
|
||||
"scopeName": "frontmatter.markdown.hugo",
|
||||
"injectTo": [
|
||||
@@ -2731,48 +2710,45 @@
|
||||
"path": "./syntaxes/frontmatter-output.tmLanguage.json"
|
||||
}
|
||||
],
|
||||
"walkthroughs": [
|
||||
{
|
||||
"id": "frontmatter.welcome",
|
||||
"title": "Get started with Front Matter",
|
||||
"description": "Discover the features of Front Matter and learn how to use the CMS for your SSG or static site.",
|
||||
"steps": [
|
||||
{
|
||||
"id": "frontmatter.welcome.init",
|
||||
"title": "Get started",
|
||||
"description": "Initial steps to get started.\n[Open dashboard](command:frontMatter.dashboard)",
|
||||
"media": {
|
||||
"markdown": "assets/walkthrough/get-started.md"
|
||||
},
|
||||
"completionEvents": [
|
||||
"onContext:frontMatterInitialized"
|
||||
]
|
||||
"walkthroughs": [{
|
||||
"id": "frontmatter.welcome",
|
||||
"title": "Get started with Front Matter",
|
||||
"description": "Discover the features of Front Matter and learn how to use the CMS for your SSG or static site.",
|
||||
"steps": [{
|
||||
"id": "frontmatter.welcome.init",
|
||||
"title": "Get started",
|
||||
"description": "Initial steps to get started.\n[Open dashboard](command:frontMatter.dashboard)",
|
||||
"media": {
|
||||
"markdown": "assets/walkthrough/get-started.md"
|
||||
},
|
||||
{
|
||||
"id": "frontmatter.welcome.documentation",
|
||||
"title": "Documentation",
|
||||
"description": "Check out the documentation for Front Matter.\n[View our documentation](https://frontmatter.codes/docs)",
|
||||
"media": {
|
||||
"markdown": "assets/walkthrough/documentation.md"
|
||||
},
|
||||
"completionEvents": [
|
||||
"onLink:https://frontmatter.codes/docs"
|
||||
]
|
||||
"completionEvents": [
|
||||
"onContext:frontMatterInitialized"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "frontmatter.welcome.documentation",
|
||||
"title": "Documentation",
|
||||
"description": "Check out the documentation for Front Matter.\n[View our documentation](https://frontmatter.codes/docs)",
|
||||
"media": {
|
||||
"markdown": "assets/walkthrough/documentation.md"
|
||||
},
|
||||
{
|
||||
"id": "frontmatter.welcome.supporter",
|
||||
"title": "Support the project",
|
||||
"description": "Become a supporter.\n[Support the project](https://github.com/sponsors/estruyf)",
|
||||
"media": {
|
||||
"markdown": "assets/walkthrough/support-the-project.md"
|
||||
},
|
||||
"completionEvents": [
|
||||
"onLink:https://github.com/sponsors/estruyf"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
"completionEvents": [
|
||||
"onLink:https://frontmatter.codes/docs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "frontmatter.welcome.supporter",
|
||||
"title": "Support the project",
|
||||
"description": "Become a supporter.\n[Support the project](https://github.com/sponsors/estruyf)",
|
||||
"media": {
|
||||
"markdown": "assets/walkthrough/support-the-project.md"
|
||||
},
|
||||
"completionEvents": [
|
||||
"onLink:https://github.com/sponsors/estruyf"
|
||||
]
|
||||
}
|
||||
]
|
||||
}]
|
||||
},
|
||||
"scripts": {
|
||||
"dev:ext": "npm run clean && npm run localization:generate && npm-run-all --parallel watch:*",
|
||||
@@ -2900,4 +2876,4 @@
|
||||
"dependencies": {
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -231,6 +231,7 @@
|
||||
"setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.when.properties.operator.description": "The operator to use",
|
||||
"setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.when.properties.value.description": "The value to compare",
|
||||
"setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.when.properties.caseSensitive.description": "Specify if the comparison is case sensitive. Default: true",
|
||||
"setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.actions.description": "Specify the field custom actions",
|
||||
"setting.frontMatter.taxonomy.contentTypes.items.properties.pageBundle.description": "Specify if you want to create a folder when creating new content.",
|
||||
"setting.frontMatter.taxonomy.contentTypes.items.properties.previewPath.description": "Defines a custom preview path for the content type.",
|
||||
"setting.frontMatter.taxonomy.contentTypes.items.properties.trailingSlash.description": "Specify if you want to add a trailing slash to the preview URL.",
|
||||
@@ -279,5 +280,6 @@
|
||||
"setting.frontMatter.taxonomy.contentTypes.items.properties.isSubContent.description": "Specify if the content type is sub content.",
|
||||
|
||||
"setting.frontMatter.git.disableOnBranches.markdownDescription": "Specify the branches on which you want to disable the Git actions. [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.git.disableonbranches) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.git.disableonbranches%22%5D)",
|
||||
"setting.frontMatter.git.requiresCommitMessage.markdownDescription": "Specify if you want to require a commit message when publishing your changes for a specified branch. [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.git.requirescommitmessage) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.git.requirescommitmessage%22%5D)"
|
||||
"setting.frontMatter.git.requiresCommitMessage.markdownDescription": "Specify if you want to require a commit message when publishing your changes for a specified branch. [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.git.requirescommitmessage) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.git.requirescommitmessage%22%5D)",
|
||||
"setting.frontMatter.copilot.family.markdownDescription": "Specify the LLM family of the Copilot you want to use. [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.copilot.family) - [View in VS Code](command:simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.copilot.family%22%5D)"
|
||||
}
|
||||
@@ -5,13 +5,15 @@ const core = require('@actions/core');
|
||||
const packageJson = require('../package.json');
|
||||
const version = packageJson.version.split('.');
|
||||
|
||||
packageJson.version = `${version[0]}.${version[1]}.${process.argv[process.argv.length-1].substr(0, 7)}`;
|
||||
packageJson.version = `${version[0]}.${version[1]}.${process.argv[
|
||||
process.argv.length - 1
|
||||
].substring(0, 9)}`;
|
||||
packageJson.preview = true;
|
||||
packageJson.name = "vscode-front-matter-beta";
|
||||
packageJson.name = 'vscode-front-matter-beta';
|
||||
packageJson.displayName = `${packageJson.displayName} (BETA)`;
|
||||
packageJson.description = `BETA Version of Front Matter. ${packageJson.description}`;
|
||||
packageJson.icon = "assets/frontmatter-beta.png";
|
||||
packageJson.homepage = "https://beta.frontmatter.codes";
|
||||
packageJson.icon = 'assets/frontmatter-beta.png';
|
||||
packageJson.homepage = 'https://beta.frontmatter.codes';
|
||||
|
||||
console.log(packageJson.version);
|
||||
|
||||
@@ -20,13 +22,16 @@ core.summary.addHeading(`Version info`).addRaw(`Version: ${packageJson.version}`
|
||||
const scripts = packageJson.scripts;
|
||||
for (const key in scripts) {
|
||||
if (key.startsWith(`prod:`)) {
|
||||
scripts[key] = scripts[key].replace("production", "development");
|
||||
scripts[key] = scripts[key].replace('production', 'development');
|
||||
}
|
||||
}
|
||||
|
||||
console.log(JSON.stringify(packageJson.scripts, null, 2));
|
||||
|
||||
fs.writeFileSync(path.join(path.resolve('.'), 'package.json'), JSON.stringify(packageJson, null, 2));
|
||||
fs.writeFileSync(
|
||||
path.join(path.resolve('.'), 'package.json'),
|
||||
JSON.stringify(packageJson, null, 2)
|
||||
);
|
||||
|
||||
let readme = fs.readFileSync(path.join(__dirname, '../README.beta.md'), 'utf8');
|
||||
fs.writeFileSync(path.join(__dirname, '../README.md'), readme);
|
||||
@@ -35,4 +40,4 @@ fs.writeFileSync(path.join(__dirname, '../README.md'), readme);
|
||||
const ignoreFilePath = path.join(path.resolve('.'), '.vscodeignore');
|
||||
let vscodeignore = fs.readFileSync(ignoreFilePath, 'utf8');
|
||||
vscodeignore = vscodeignore.replace(`**/*.map`, '');
|
||||
fs.writeFileSync(ignoreFilePath, vscodeignore);
|
||||
fs.writeFileSync(ignoreFilePath, vscodeignore);
|
||||
|
||||
@@ -20,7 +20,6 @@ import {
|
||||
SETTING_SLUG_PREFIX,
|
||||
SETTING_SLUG_SUFFIX,
|
||||
SETTING_CONTENT_PLACEHOLDERS,
|
||||
TelemetryEvent,
|
||||
SETTING_SLUG_TEMPLATE
|
||||
} from './../constants';
|
||||
import { CustomPlaceholder, Field } from '../models';
|
||||
@@ -39,13 +38,13 @@ import { COMMAND_NAME, DefaultFields } from '../constants';
|
||||
import { DashboardData, SnippetInfo, SnippetRange } from '../models/DashboardData';
|
||||
import { DateHelper } from '../helpers/DateHelper';
|
||||
import { parseWinPath } from '../helpers/parseWinPath';
|
||||
import { Telemetry } from '../helpers/Telemetry';
|
||||
import { ParsedFrontMatter } from '../parsers';
|
||||
import { MediaListener } from '../listeners/panel';
|
||||
import { NavigationType } from '../dashboardWebView/models';
|
||||
import { SNIPPET } from '../constants/Snippet';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
import { getTitleField } from '../utils';
|
||||
|
||||
export class Article {
|
||||
/**
|
||||
@@ -191,8 +190,6 @@ export class Article {
|
||||
* Generate the slug based on the article title
|
||||
*/
|
||||
public static async updateSlug() {
|
||||
Telemetry.send(TelemetryEvent.generateSlug);
|
||||
|
||||
const updateFileName = Settings.get(SETTING_SLUG_UPDATE_FILE_NAME) as string;
|
||||
const editor = window.activeTextEditor;
|
||||
|
||||
@@ -213,7 +210,7 @@ export class Article {
|
||||
contentType
|
||||
);
|
||||
|
||||
const titleField = 'title';
|
||||
const titleField = getTitleField();
|
||||
const articleTitle: string = article.data[titleField];
|
||||
const slugInfo = Article.generateSlug(articleTitle, article, contentType.slugTemplate);
|
||||
|
||||
@@ -307,17 +304,18 @@ export class Article {
|
||||
|
||||
const parsedFile = parse(file);
|
||||
|
||||
const titleField = getTitleField();
|
||||
const slugTemplate = Settings.get<string>(SETTING_SLUG_TEMPLATE);
|
||||
if (slugTemplate) {
|
||||
if (slugTemplate === '{{title}}') {
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
if (article?.data?.title) {
|
||||
return article.data.title.toLowerCase().replace(/\s/g, '-');
|
||||
if (article?.data && article.data[titleField]) {
|
||||
return article.data[titleField].toLowerCase().replace(/\s/g, '-');
|
||||
}
|
||||
} else {
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
if (article?.data) {
|
||||
return SlugHelper.createSlug(article.data.title, article.data, slugTemplate);
|
||||
return SlugHelper.createSlug(article.data[titleField], article.data, slugTemplate);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -490,11 +488,12 @@ export class Article {
|
||||
|
||||
const article = ArticleHelper.getFrontMatter(editor);
|
||||
const contentType = article ? await ArticleHelper.getContentType(article) : undefined;
|
||||
const tileField = getTitleField();
|
||||
|
||||
await commands.executeCommand(COMMAND_NAME.dashboard, {
|
||||
type: NavigationType.Snippets,
|
||||
data: {
|
||||
fileTitle: article?.data.title || '',
|
||||
fileTitle: article?.data[tileField] || '',
|
||||
filePath: editor.document.uri.fsPath,
|
||||
fieldName: basename(editor.document.uri.fsPath),
|
||||
contentType,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { authentication, commands, ExtensionContext } from 'vscode';
|
||||
import { COMMAND_NAME, CONTEXT } from '../constants';
|
||||
import { COMMAND_NAME, CONTEXT, WEBSITE_LINKS } from '../constants';
|
||||
import { Extension, Logger } from '../helpers';
|
||||
import { Dashboard } from './Dashboard';
|
||||
import { SettingsListener } from '../listeners/panel';
|
||||
@@ -22,9 +22,8 @@ export class Backers {
|
||||
const githubAuth = await authentication.getSession('github', ['read:user'], { silent: true });
|
||||
if (githubAuth && githubAuth.accessToken) {
|
||||
try {
|
||||
const isBeta = ext.isBetaVersion();
|
||||
const response = await fetch(
|
||||
`https://${isBeta ? `beta.` : ``}frontmatter.codes/api/v2/backers`,
|
||||
`${WEBSITE_LINKS.api.baseUrl}${WEBSITE_LINKS.api.endpoints.backers}`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Telemetry } from './../helpers/Telemetry';
|
||||
import { TelemetryEvent, PreviewCommands, GeneralCommands } from './../constants';
|
||||
import { PreviewCommands, GeneralCommands } from './../constants';
|
||||
import { join } from 'path';
|
||||
import { commands, Uri, ViewColumn, window } from 'vscode';
|
||||
import { Extension } from '../helpers';
|
||||
@@ -116,7 +115,5 @@ export class Chatbot {
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
Telemetry.send(TelemetryEvent.openChatbot);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,7 @@ import {
|
||||
CONTEXT,
|
||||
ExtensionState,
|
||||
SETTING_EXPERIMENTAL,
|
||||
SETTING_EXTENSIBILITY_SCRIPTS,
|
||||
COMMAND_NAME,
|
||||
TelemetryEvent
|
||||
COMMAND_NAME
|
||||
} from '../constants';
|
||||
import { join } from 'path';
|
||||
import { commands, Uri, ViewColumn, Webview, WebviewPanel, window } from 'vscode';
|
||||
@@ -18,7 +16,6 @@ import {
|
||||
DashboardListener,
|
||||
MediaListener,
|
||||
SettingsListener,
|
||||
TelemetryListener,
|
||||
DataListener,
|
||||
PagesListener,
|
||||
ExtensionListener,
|
||||
@@ -29,12 +26,11 @@ import {
|
||||
} from '../listeners/dashboard';
|
||||
import { MediaListener as PanelMediaListener } from '../listeners/panel';
|
||||
import { GitListener, ModeListener } from '../listeners/general';
|
||||
import { Folders } from './Folders';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
import { DashboardMessage } from '../dashboardWebView/DashboardMessage';
|
||||
import { NavigationType } from '../dashboardWebView/models';
|
||||
import { ignoreMsgCommand } from '../utils';
|
||||
import { getExtensibilityScripts, ignoreMsgCommand } from '../utils';
|
||||
|
||||
export class Dashboard {
|
||||
private static webview: WebviewPanel | null = null;
|
||||
@@ -67,7 +63,6 @@ export class Dashboard {
|
||||
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.dashboard, (data?: DashboardData) => {
|
||||
Telemetry.send(TelemetryEvent.openContentDashboard);
|
||||
if (!data) {
|
||||
Dashboard.open({ type: NavigationType.Contents });
|
||||
} else {
|
||||
@@ -78,35 +73,30 @@ export class Dashboard {
|
||||
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.dashboardMedia, () => {
|
||||
Telemetry.send(TelemetryEvent.openMediaDashboard);
|
||||
Dashboard.open({ type: NavigationType.Media });
|
||||
})
|
||||
);
|
||||
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.dashboardSnippets, () => {
|
||||
Telemetry.send(TelemetryEvent.openSnippetsDashboard);
|
||||
Dashboard.open({ type: NavigationType.Snippets });
|
||||
})
|
||||
);
|
||||
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.dashboardData, () => {
|
||||
Telemetry.send(TelemetryEvent.openDataDashboard);
|
||||
Dashboard.open({ type: NavigationType.Data });
|
||||
})
|
||||
);
|
||||
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.dashboardTaxonomy, () => {
|
||||
Telemetry.send(TelemetryEvent.openTaxonomyDashboard);
|
||||
Dashboard.open({ type: NavigationType.Taxonomy });
|
||||
})
|
||||
);
|
||||
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.dashboardClose, () => {
|
||||
Telemetry.send(TelemetryEvent.closeDashboard);
|
||||
Dashboard.close();
|
||||
})
|
||||
);
|
||||
@@ -241,7 +231,6 @@ export class Dashboard {
|
||||
PagesListener.process(msg);
|
||||
SettingsListener.process(msg);
|
||||
DataListener.process(msg);
|
||||
TelemetryListener.process(msg);
|
||||
SnippetListener.process(msg);
|
||||
ModeListener.process(msg);
|
||||
GitListener.process(msg);
|
||||
@@ -307,20 +296,8 @@ export class Dashboard {
|
||||
|
||||
// Get experimental setting
|
||||
const experimental = SettingsHelper.get(SETTING_EXPERIMENTAL);
|
||||
const extensibilityScripts = SettingsHelper.get<string[]>(SETTING_EXTENSIBILITY_SCRIPTS) || [];
|
||||
|
||||
const scriptsToLoad: string[] = [];
|
||||
if (experimental) {
|
||||
for (const script of extensibilityScripts) {
|
||||
if (script.startsWith('https://')) {
|
||||
scriptsToLoad.push(script);
|
||||
} else {
|
||||
const absScriptPath = Folders.getAbsFilePath(script);
|
||||
const scriptUri = webView.asWebviewUri(Uri.file(absScriptPath));
|
||||
scriptsToLoad.push(scriptUri.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
const scriptsToLoad: string[] = getExtensibilityScripts(webView);
|
||||
|
||||
const csp = [
|
||||
`default-src 'none';`,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Folders } from './Folders';
|
||||
import { ViewColumn, commands, workspace } from 'vscode';
|
||||
import { ViewColumn, commands, version, workspace } from 'vscode';
|
||||
import ContentProvider from '../providers/ContentProvider';
|
||||
import { join } from 'path';
|
||||
import { ContentFolder } from '../models';
|
||||
@@ -37,6 +37,8 @@ export class Diagnostics {
|
||||
|
||||
Beta: \`${Extension.getInstance().isBetaVersion()}\`
|
||||
Version: \`${Extension.getInstance().version}\`
|
||||
OS: \`${process.platform}\`
|
||||
VSCode version: \`${version}\`
|
||||
|
||||
## Project name
|
||||
|
||||
|
||||
@@ -6,8 +6,7 @@ import {
|
||||
SETTING_CONTENT_PAGE_FOLDERS,
|
||||
SETTING_CONTENT_STATIC_FOLDER,
|
||||
SETTING_CONTENT_SUPPORTED_FILETYPES,
|
||||
SETTING_DATE_FORMAT,
|
||||
TelemetryEvent
|
||||
SETTING_DATE_FORMAT
|
||||
} from './../constants';
|
||||
import { commands, Uri, workspace, window } from 'vscode';
|
||||
import { basename, dirname, join, relative, sep } from 'path';
|
||||
@@ -30,10 +29,9 @@ import { parseWinPath } from '../helpers/parseWinPath';
|
||||
import { MediaHelpers } from '../helpers/MediaHelpers';
|
||||
import { MediaListener, PagesListener, SettingsListener } from '../listeners/dashboard';
|
||||
import { DEFAULT_FILE_TYPES } from '../constants/DefaultFileTypes';
|
||||
import { Telemetry } from '../helpers/Telemetry';
|
||||
import { glob } from 'glob';
|
||||
import { mkdirAsync } from '../utils/mkdirAsync';
|
||||
import { existsAsync, isWindows } from '../utils';
|
||||
import { existsAsync, isWindows, lstatAsync } from '../utils';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
import { Preview } from './Preview';
|
||||
@@ -107,8 +105,6 @@ export class Folders {
|
||||
MediaHelpers.resetMedia();
|
||||
MediaListener.sendMediaFiles(0, folderPath);
|
||||
}
|
||||
|
||||
Telemetry.send(TelemetryEvent.addMediaFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -183,8 +179,6 @@ export class Folders {
|
||||
|
||||
Notifications.info(l10n.t(LocalizationKey.commandsFoldersCreateSuccess));
|
||||
|
||||
Telemetry.send(TelemetryEvent.registerFolder);
|
||||
|
||||
SettingsListener.getSettings(true);
|
||||
}
|
||||
}
|
||||
@@ -198,8 +192,6 @@ export class Folders {
|
||||
let folders = await Folders.get();
|
||||
folders = folders.filter((f) => f.path !== folder.fsPath);
|
||||
await Folders.update(folders);
|
||||
|
||||
Telemetry.send(TelemetryEvent.unregisterFolder);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -835,9 +827,26 @@ export class Folders {
|
||||
|
||||
try {
|
||||
pattern = isWindows() ? parseWinPath(pattern) : pattern;
|
||||
const files = await glob(pattern, { ignore: '**/node_modules/**', dot: true });
|
||||
const allFolders = (files || []).map((file) => dirname(file));
|
||||
const uniqueFolders = [...new Set(allFolders)];
|
||||
const folders = await glob(pattern, {
|
||||
ignore: 'node_modules/**',
|
||||
dot: true
|
||||
});
|
||||
|
||||
const onlyFolders = [];
|
||||
for (const folder of folders) {
|
||||
try {
|
||||
const stats = await lstatAsync(folder);
|
||||
if (stats.isDirectory()) {
|
||||
onlyFolders.push(folder);
|
||||
} else {
|
||||
onlyFolders.push(dirname(folder));
|
||||
}
|
||||
} catch (e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const uniqueFolders = [...new Set(onlyFolders)];
|
||||
Logger.verbose(`Folders:findFolders:end - ${uniqueFolders.length}`);
|
||||
return uniqueFolders;
|
||||
} catch (e) {
|
||||
@@ -856,7 +865,7 @@ export class Folders {
|
||||
|
||||
try {
|
||||
pattern = isWindows() ? parseWinPath(pattern) : pattern;
|
||||
const files = await glob(pattern, { ignore: '**/node_modules/**', dot: true });
|
||||
const files = await glob(pattern, { ignore: 'node_modules/**', dot: true });
|
||||
const allFiles = (files || []).map((file) => Uri.file(file));
|
||||
Logger.verbose(`Folders:findFiles:end - ${allFiles.length}`);
|
||||
return allFiles;
|
||||
|
||||
@@ -2,7 +2,6 @@ import {
|
||||
SETTING_PREVIEW_HOST,
|
||||
SETTING_PREVIEW_PATHNAME,
|
||||
CONTEXT,
|
||||
TelemetryEvent,
|
||||
PreviewCommands,
|
||||
SETTING_EXPERIMENTAL,
|
||||
SETTING_DATE_FORMAT,
|
||||
@@ -20,7 +19,6 @@ import {
|
||||
processFmPlaceholders,
|
||||
processPathPlaceholders,
|
||||
Settings,
|
||||
Telemetry,
|
||||
processDateTimePlaceholders
|
||||
} from '../helpers';
|
||||
import { ContentFolder, ContentType, PreviewSettings } from '../models';
|
||||
@@ -31,7 +29,7 @@ import { ParsedFrontMatter } from '../parsers';
|
||||
import { getLocalizationFile } from '../utils/getLocalizationFile';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
import { joinUrl } from '../utils';
|
||||
import { getTitleField, joinUrl } from '../utils';
|
||||
import { i18n } from './i18n';
|
||||
|
||||
export class Preview {
|
||||
@@ -77,11 +75,13 @@ export class Preview {
|
||||
return;
|
||||
}
|
||||
|
||||
const titleField = getTitleField();
|
||||
|
||||
// Create the preview webview
|
||||
const webView = window.createWebviewPanel(
|
||||
'frontMatterPreview',
|
||||
article?.data?.title
|
||||
? l10n.t(LocalizationKey.commandsPreviewPanelTitle, article?.data.title)
|
||||
article?.data && article?.data[titleField]
|
||||
? l10n.t(LocalizationKey.commandsPreviewPanelTitle, article?.data[titleField])
|
||||
: 'Front Matter Preview',
|
||||
{
|
||||
viewColumn: ViewColumn.Beside,
|
||||
@@ -197,8 +197,6 @@ export class Preview {
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
Telemetry.send(TelemetryEvent.openPreview);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { DEFAULT_CONTENT_TYPE } from './../constants/ContentType';
|
||||
import { Telemetry } from './../helpers/Telemetry';
|
||||
import { workspace, Uri, commands, window } from 'vscode';
|
||||
import { join } from 'path';
|
||||
import { Notifications } from '../helpers/Notifications';
|
||||
@@ -16,8 +15,7 @@ import {
|
||||
import {
|
||||
COMMAND_NAME,
|
||||
SETTING_CONTENT_DEFAULT_FILETYPE,
|
||||
SETTING_TAXONOMY_CONTENT_TYPES,
|
||||
TelemetryEvent
|
||||
SETTING_TAXONOMY_CONTENT_TYPES
|
||||
} from '../constants';
|
||||
import { SettingsListener } from '../listeners/dashboard';
|
||||
import { existsAsync, writeFileAsync } from '../utils';
|
||||
@@ -96,8 +94,6 @@ categories: []
|
||||
// Initialize the taxonomy database
|
||||
TaxonomyHelper.initDb();
|
||||
|
||||
Telemetry.send(TelemetryEvent.initialization);
|
||||
|
||||
// Check if you can find the framework
|
||||
const wsFolder = Folders.getWorkspaceFolder();
|
||||
const framework = await FrameworkDetector.get(wsFolder?.fsPath || '');
|
||||
|
||||
@@ -3,15 +3,12 @@ import {
|
||||
CONTEXT,
|
||||
EXTENSION_NAME,
|
||||
NOTIFICATION_TYPE,
|
||||
SETTING_SEO_DESCRIPTION_FIELD,
|
||||
SETTING_SEO_DESCRIPTION_LENGTH,
|
||||
SETTING_SEO_TITLE_FIELD,
|
||||
SETTING_SEO_TITLE_LENGTH
|
||||
} from './../constants';
|
||||
import * as vscode from 'vscode';
|
||||
import { ArticleHelper, Notifications, SeoHelper, Settings } from '../helpers';
|
||||
import { PanelProvider } from '../panelWebView/PanelProvider';
|
||||
import { DefaultFields } from '../constants';
|
||||
import { ContentType } from '../helpers/ContentType';
|
||||
import { DataListener } from '../listeners/panel';
|
||||
import { commands } from 'vscode';
|
||||
@@ -20,6 +17,7 @@ import { Preview } from './Preview';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
import { i18n } from './i18n';
|
||||
import { getDescriptionField, getTitleField } from '../utils';
|
||||
|
||||
export class StatusListener {
|
||||
/**
|
||||
@@ -56,12 +54,10 @@ export class StatusListener {
|
||||
collection.clear();
|
||||
|
||||
// Retrieve the SEO config properties
|
||||
const titleLength = (Settings.get(SETTING_SEO_TITLE_LENGTH) as number) || -1;
|
||||
const descLength = (Settings.get(SETTING_SEO_DESCRIPTION_LENGTH) as number) || -1;
|
||||
const titleField =
|
||||
(Settings.get(SETTING_SEO_TITLE_FIELD) as string) || DefaultFields.Title;
|
||||
const descriptionField =
|
||||
(Settings.get(SETTING_SEO_DESCRIPTION_FIELD) as string) || DefaultFields.Description;
|
||||
const titleLength = Settings.get<number>(SETTING_SEO_TITLE_LENGTH) || -1;
|
||||
const descLength = Settings.get<number>(SETTING_SEO_DESCRIPTION_LENGTH) || -1;
|
||||
const titleField = getTitleField();
|
||||
const descriptionField = getDescriptionField();
|
||||
|
||||
if (editor && article.data[titleField] && titleLength > -1) {
|
||||
SeoHelper.checkLength(editor, collection, article, titleField, titleLength);
|
||||
|
||||
33
src/commands/Taxonomy.ts
Normal file
33
src/commands/Taxonomy.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { commands } from 'vscode';
|
||||
import { COMMAND_NAME } from '../constants';
|
||||
import { TagType } from '../panelWebView/TagType';
|
||||
import { PanelProvider } from '../panelWebView/PanelProvider';
|
||||
|
||||
export class Taxonomy {
|
||||
/**
|
||||
* Registers the commands for the Article class.
|
||||
*
|
||||
* @param subscriptions - The array of subscriptions to register the commands with.
|
||||
*/
|
||||
public static async registerCommands(subscriptions: unknown[]) {
|
||||
const explorerSidebar = PanelProvider.getInstance();
|
||||
|
||||
if (explorerSidebar) {
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.insertTags, async () => {
|
||||
await commands.executeCommand('workbench.view.extension.frontmatter-explorer');
|
||||
await commands.executeCommand('workbench.action.focusSideBar');
|
||||
explorerSidebar.triggerInputFocus(TagType.tags);
|
||||
})
|
||||
);
|
||||
|
||||
subscriptions.push(
|
||||
commands.registerCommand(COMMAND_NAME.insertCategories, async () => {
|
||||
await commands.executeCommand('workbench.view.extension.frontmatter-explorer');
|
||||
await commands.executeCommand('workbench.action.focusSideBar');
|
||||
explorerSidebar.triggerInputFocus(TagType.categories);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,9 @@ import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import {
|
||||
COMMAND_NAME,
|
||||
DefaultFields,
|
||||
SETTING_CONTENT_DEFAULT_FILETYPE,
|
||||
SETTING_TEMPLATES_FOLDER,
|
||||
TelemetryEvent
|
||||
SETTING_TEMPLATES_FOLDER
|
||||
} from '../constants';
|
||||
import { ArticleHelper, Extension, Settings } from '../helpers';
|
||||
import { Article, Folders } from '.';
|
||||
@@ -15,7 +15,6 @@ import { ContentType } from '../helpers/ContentType';
|
||||
import { ContentType as IContentType } from '../models';
|
||||
import { PagesListener } from '../listeners/dashboard';
|
||||
import { extname } from 'path';
|
||||
import { Telemetry } from '../helpers/Telemetry';
|
||||
import { writeFileAsync, copyFileAsync } from '../utils';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
@@ -163,8 +162,14 @@ export class Template {
|
||||
|
||||
const templateData = await ArticleHelper.getFrontMatterByPath(template.fsPath);
|
||||
let contentType: IContentType | undefined;
|
||||
if (templateData && templateData.data && templateData.data.type) {
|
||||
contentType = contentTypes?.find((t) => t.name === templateData.data.type);
|
||||
if (templateData && templateData.data) {
|
||||
if (templateData.data[DefaultFields.ContentType]) {
|
||||
contentType = contentTypes?.find(
|
||||
(t) => t.name === templateData.data[DefaultFields.ContentType]
|
||||
);
|
||||
} else if (templateData.data[DefaultFields.Type]) {
|
||||
contentType = contentTypes?.find((t) => t.name === templateData.data[DefaultFields.Type]);
|
||||
}
|
||||
}
|
||||
|
||||
const fileExtension = extname(template.fsPath).replace('.', '');
|
||||
@@ -217,8 +222,6 @@ export class Template {
|
||||
|
||||
Notifications.info(l10n.t(LocalizationKey.commandsTemplateCreateSuccess));
|
||||
|
||||
Telemetry.send(TelemetryEvent.createContentFromTemplate);
|
||||
|
||||
// Trigger a refresh for the dashboard
|
||||
PagesListener.refresh();
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
import { COMMAND_NAME, SETTING_CONTENT_I18N } from '../constants';
|
||||
import { ContentFolder, Field, I18nConfig, ContentType as IContentType } from '../models';
|
||||
import { join, parse } from 'path';
|
||||
import { existsAsync } from '../utils';
|
||||
import { existsAsync, getDescriptionField, getTitleField } from '../utils';
|
||||
import { Folders } from '.';
|
||||
import { ParsedFrontMatter } from '../parsers';
|
||||
import { PagesListener } from '../listeners/dashboard';
|
||||
@@ -412,8 +412,11 @@ export class i18n {
|
||||
},
|
||||
async () => {
|
||||
try {
|
||||
const title = article.data.title || '';
|
||||
const description = article.data.description || '';
|
||||
const titleField = getTitleField();
|
||||
const descriptionField = getDescriptionField();
|
||||
|
||||
const title = article.data[titleField] || '';
|
||||
const description = article.data[descriptionField] || '';
|
||||
const content = article.content || '';
|
||||
|
||||
const text = [title, description, content];
|
||||
@@ -428,8 +431,8 @@ export class i18n {
|
||||
return;
|
||||
}
|
||||
|
||||
article.data.title = article.data.title ? translations[0] : '';
|
||||
article.data.description = article.data.description ? translations[1] : '';
|
||||
article.data[titleField] = article.data[titleField] ? translations[0] : '';
|
||||
article.data[descriptionField] = article.data[descriptionField] ? translations[1] : '';
|
||||
article.content = article.content ? translations[2] : '';
|
||||
} catch (error) {
|
||||
Notifications.error(`${(error as Error).message}`);
|
||||
|
||||
@@ -10,5 +10,7 @@ export * from './Preview';
|
||||
export * from './Project';
|
||||
export * from './Settings';
|
||||
export * from './StatusListener';
|
||||
export * from './Taxonomy';
|
||||
export * from './Template';
|
||||
export * from './Wysiwyg';
|
||||
export * from './i18n';
|
||||
|
||||
@@ -3,5 +3,8 @@ export const DefaultFields = {
|
||||
LastModified: `lastmod`,
|
||||
Description: `description`,
|
||||
Title: `title`,
|
||||
Slug: `slug`
|
||||
Slug: `slug`,
|
||||
Type: `type`,
|
||||
ContentType: `fmContentType`,
|
||||
Keywords: `keywords`
|
||||
};
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
const extensionName = 'frontMatter';
|
||||
export const EXTENSION_COMMAND_PREFIX = 'frontMatter';
|
||||
|
||||
export const EXTENSION_ID = 'eliostruyf.vscode-front-matter';
|
||||
export const EXTENSION_BETA_ID = 'eliostruyf.vscode-front-matter-beta';
|
||||
|
||||
export const getCommandName = (command: string) => {
|
||||
return `${extensionName}.${command}`;
|
||||
return `${EXTENSION_COMMAND_PREFIX}.${command}`;
|
||||
};
|
||||
|
||||
export const COMMAND_NAME = {
|
||||
|
||||
@@ -14,8 +14,20 @@ export const DOCS_SUBMODULES = 'https://frontmatter.codes/docs/git-integration#g
|
||||
export const WEBSITE_LINKS = {
|
||||
root: 'https://frontmatter.codes',
|
||||
api: {
|
||||
metrics: 'https://frontmatter.codes/api/metrics',
|
||||
ai: 'https://frontmatter.codes/api/ai'
|
||||
baseUrl: 'https://api.frontmatter.codes',
|
||||
endpoints: {
|
||||
ai: {
|
||||
description: '/ai/description',
|
||||
taxonomy: '/ai/taxonomy',
|
||||
title: '/ai/title'
|
||||
},
|
||||
chat: {
|
||||
init: '/ai-init',
|
||||
message: '/ai-chat',
|
||||
feedback: '/ai-feedback'
|
||||
},
|
||||
backers: '/v2/backers'
|
||||
}
|
||||
},
|
||||
docs: {
|
||||
dataDashboard: 'https://frontmatter.codes/docs/dashboard/datafiles-view',
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
export const TelemetryEvent = {
|
||||
activate: 'activate',
|
||||
initialization: 'initialization',
|
||||
registerFolder: 'registerFolder',
|
||||
unregisterFolder: 'unregisterFolder',
|
||||
promoteSettings: 'promoteSettings',
|
||||
|
||||
// Commands
|
||||
openContentDashboard: 'openContentDashboard',
|
||||
openMediaDashboard: 'openMediaDashboard',
|
||||
openDataDashboard: 'openDataDashboard',
|
||||
openSnippetsDashboard: 'openSnippetsDashboard',
|
||||
openTaxonomyDashboard: 'openTaxonomyDashboard',
|
||||
closeDashboard: 'closeDashboard',
|
||||
|
||||
// Other actions
|
||||
generateSlug: 'generateSlug',
|
||||
createContentFromTemplate: 'createContentFromTemplate',
|
||||
createContentFromContentType: 'createContentFromContentType',
|
||||
addMediaFolder: 'addMediaFolder',
|
||||
openPreview: 'openPreview',
|
||||
uploadMedia: 'uploadMedia',
|
||||
refreshMedia: 'refreshMedia',
|
||||
deleteMedia: 'deleteMedia',
|
||||
insertContentSnippet: 'insertContentSnippet',
|
||||
insertMediaToContent: 'insertMediaToContent',
|
||||
insertFileToContent: 'insertFileToContent',
|
||||
updateMediaMetadata: 'updateMediaMetadata',
|
||||
openPanelWebview: 'openPanelWebview',
|
||||
|
||||
// Chatbot
|
||||
openChatbot: 'openChatbot',
|
||||
|
||||
// Content types
|
||||
generateContentType: 'generateContentType',
|
||||
addMissingFields: 'addMissingFields',
|
||||
setContentType: 'setContentType',
|
||||
|
||||
// Custom scripts
|
||||
runCustomScript: 'runCustomScript',
|
||||
runMediaScript: 'runMediaScript',
|
||||
|
||||
// Webviews
|
||||
webviewWelcomeScreen: 'webviewWelcomeScreen',
|
||||
webviewMediaView: 'webviewMediaView',
|
||||
webviewDataView: 'webviewDataView',
|
||||
webviewContentsView: 'webviewContentsView',
|
||||
webviewSnippetsView: 'webviewSnippetsView',
|
||||
webviewTaxonomyDashboard: 'webviewTaxonomyDashboard',
|
||||
webviewSettings: 'webviewSettings',
|
||||
webviewUnknown: 'webviewUnknown',
|
||||
|
||||
// Git
|
||||
gitSync: 'gitSync',
|
||||
gitFetch: 'gitFetch'
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from './ContentType';
|
||||
export * from './DefaultFeatureFlags';
|
||||
export * from './DefaultFieldValues';
|
||||
export * from './DefaultFields';
|
||||
export * from './DefaultFileTypes';
|
||||
@@ -17,7 +18,6 @@ export * from './SentryIgnore';
|
||||
export * from './Snippet';
|
||||
export * from './SsgScripts';
|
||||
export * from './StaticFolderPlaceholder';
|
||||
export * from './TelemetryEvent';
|
||||
export * from './Templates';
|
||||
export * from './charCode';
|
||||
export * from './charMap';
|
||||
|
||||
@@ -45,8 +45,6 @@ export const SETTING_TEMPLATES_FOLDER = 'templates.folder';
|
||||
export const SETTING_TEMPLATES_PREFIX = 'templates.prefix';
|
||||
export const SETTING_TEMPLATES_ENABLED = 'templates.enabled';
|
||||
|
||||
export const SETTING_TELEMETRY_DISABLE = 'telemetry.disable';
|
||||
|
||||
export const SETTING_PANEL_FREEFORM = 'panel.freeform';
|
||||
export const SETTING_PANEL_ACTIONS_DISABLED = 'panel.actions.disabled';
|
||||
|
||||
@@ -115,6 +113,8 @@ export const SETTING_SNIPPETS_WRAPPER = 'snippets.wrapper.enabled';
|
||||
|
||||
export const SETTING_WEBSITE_URL = 'website.host';
|
||||
|
||||
export const SETTING_COPILOT_FAMILY = 'copilot.family';
|
||||
|
||||
export const SETTING_LOGGING = 'logging';
|
||||
|
||||
/**
|
||||
|
||||
@@ -74,7 +74,6 @@ export enum DashboardMessage {
|
||||
setState = 'setState',
|
||||
getState = 'getState',
|
||||
runCustomScript = 'runCustomScript',
|
||||
sendTelemetry = 'sendTelemetry',
|
||||
showNotification = 'showNotification',
|
||||
setTitle = 'setTitle',
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { AiInitResponse } from './models/AiInitResponse';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../../localization';
|
||||
import { messageHandler } from '@estruyf/vscode/dist/client';
|
||||
import { GeneralCommands } from '../../../constants';
|
||||
import { GeneralCommands, WEBSITE_LINKS } from '../../../constants';
|
||||
|
||||
export interface IChatbotProps { }
|
||||
|
||||
@@ -36,7 +36,7 @@ export const Chatbot: React.FunctionComponent<IChatbotProps> = ({ }: React.Props
|
||||
setLocaleReady(true);
|
||||
});
|
||||
|
||||
const initResponse = await fetch(`${aiUrl}/api/ai-init`);
|
||||
const initResponse = await fetch(`${aiUrl}${WEBSITE_LINKS.api.endpoints.chat.init}`);
|
||||
|
||||
if (!initResponse.ok) {
|
||||
return;
|
||||
@@ -70,7 +70,7 @@ export const Chatbot: React.FunctionComponent<IChatbotProps> = ({ }: React.Props
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await fetch(`${aiUrl}/api/ai-chat`, {
|
||||
const response = await fetch(`${aiUrl}${WEBSITE_LINKS.api.endpoints.chat.message}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -3,6 +3,7 @@ import { HandThumbDownIcon, HandThumbUpIcon } from '@heroicons/react/24/outline'
|
||||
import { HandThumbDownIcon as ThumbDownSolidIcon, HandThumbUpIcon as ThumbUpSolidIcon } from '@heroicons/react/24/solid';
|
||||
import { useCallback } from 'react';
|
||||
import { useSettingsContext } from '../../providers/SettingsProvider';
|
||||
import { WEBSITE_LINKS } from '../../../constants';
|
||||
|
||||
export interface IFeedbackProps {
|
||||
answerId: number;
|
||||
@@ -28,7 +29,7 @@ export const Feedback: React.FunctionComponent<IFeedbackProps> = ({
|
||||
}, []);
|
||||
|
||||
const callVote = useCallback(async (vote: boolean) => {
|
||||
await fetch(`${aiUrl}/api/ai-feedback`, {
|
||||
await fetch(`${aiUrl}${WEBSITE_LINKS.api.endpoints.chat.feedback}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -10,7 +10,7 @@ import usePages from '../../hooks/usePages';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { Messenger, messageHandler } from '@estruyf/vscode/dist/client';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
import { GeneralCommands, TelemetryEvent } from '../../../constants';
|
||||
import { GeneralCommands } from '../../../constants';
|
||||
import { PageLayout } from '../Layout/PageLayout';
|
||||
import { FilesProvider } from '../../providers/FilesProvider';
|
||||
import { Alert } from '../Modals/Alert';
|
||||
@@ -67,10 +67,6 @@ export const Contents: React.FunctionComponent<IContentsProps> = ({
|
||||
}, [JSON.stringify(pageItems)]);
|
||||
|
||||
useEffect(() => {
|
||||
Messenger.send(DashboardMessage.sendTelemetry, {
|
||||
event: TelemetryEvent.webviewContentsView
|
||||
});
|
||||
|
||||
Messenger.send(DashboardMessage.setTitle, l10n.t(LocalizationKey.dashboardHeaderTabsContents));
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ export const Item: React.FunctionComponent<IItemProps> = ({
|
||||
date: pageData.date,
|
||||
title: pageData.title,
|
||||
description: pageData.description,
|
||||
type: pageData.type,
|
||||
type: pageData.fmContentType,
|
||||
pageData
|
||||
});
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { groupBy } from '../../../helpers/GroupBy';
|
||||
import { FrontMatterIcon } from '../../../panelWebView/components/Icons/FrontMatterIcon';
|
||||
import { GroupOption } from '../../constants/GroupOption';
|
||||
import { GroupingSelector, PageAtom, ViewSelector } from '../../state';
|
||||
import { GroupingSelector, PageAtom, PagedItems, ViewSelector } from '../../state';
|
||||
import { Item } from './Item';
|
||||
import { List } from './List';
|
||||
import usePagination from '../../hooks/usePagination';
|
||||
@@ -34,6 +34,7 @@ export const Overview: React.FunctionComponent<IOverviewProps> = ({
|
||||
const page = useRecoilValue(PageAtom);
|
||||
const { pageSetNr } = usePagination(settings?.dashboardState.contents.pagination);
|
||||
const view = useRecoilValue(ViewSelector);
|
||||
const [, setPagedItems] = useRecoilState(PagedItems);
|
||||
|
||||
const pagedPages = useMemo(() => {
|
||||
if (pageSetNr) {
|
||||
@@ -100,6 +101,10 @@ export const Overview: React.FunctionComponent<IOverviewProps> = ({
|
||||
return { groupKeys, groupedPages };
|
||||
}, [pages, grouping, settings?.draftField]);
|
||||
|
||||
React.useEffect(() => {
|
||||
setPagedItems(pagedPages.map((page) => page.fmFilePath));
|
||||
}, [pagedPages]);
|
||||
|
||||
React.useEffect(() => {
|
||||
messageHandler.request<string[]>(DashboardMessage.getPinnedItems).then((items) => {
|
||||
setIsReady(true);
|
||||
|
||||
@@ -17,7 +17,7 @@ import { Container } from './SortableContainer';
|
||||
import { SortableItem } from './SortableItem';
|
||||
import { ChevronRightIcon, CircleStackIcon } from '@heroicons/react/24/outline';
|
||||
import { DataType } from '../../../models/DataType';
|
||||
import { GeneralCommands, TelemetryEvent, WEBSITE_LINKS } from '../../../constants';
|
||||
import { GeneralCommands, WEBSITE_LINKS } from '../../../constants';
|
||||
import { NavigationItem } from '../Layout';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../../localization';
|
||||
@@ -130,10 +130,6 @@ export const DataView: React.FunctionComponent<IDataViewProps> = (
|
||||
|
||||
Messenger.send(DashboardMessage.setTitle, l10n.t(LocalizationKey.dashboardHeaderTabsData));
|
||||
|
||||
Messenger.send(DashboardMessage.sendTelemetry, {
|
||||
event: TelemetryEvent.webviewDataView
|
||||
});
|
||||
|
||||
Messenger.send(GeneralCommands.toVSCode.logging.info, {
|
||||
message: 'Data view loaded',
|
||||
location: 'DASHBOARD'
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as React from 'react';
|
||||
import { NavigationType, Page } from '../../models';
|
||||
import { CommandLineIcon, PencilIcon, TrashIcon, ChevronDownIcon, XMarkIcon, EyeIcon, LanguageIcon } from '@heroicons/react/24/outline';
|
||||
import { CommandLineIcon, PencilIcon, TrashIcon, ChevronDownIcon, XMarkIcon, EyeIcon, LanguageIcon, CheckIcon } from '@heroicons/react/24/outline';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { MultiSelectedItemsAtom, SelectedItemActionAtom, SelectedMediaFolderSelector, SettingsSelector } from '../../state';
|
||||
import { MultiSelectedItemsAtom, PagedItems, SelectedItemActionAtom, SelectedMediaFolderSelector, SettingsSelector } from '../../state';
|
||||
import { ActionsBarItem } from './ActionsBarItem';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../../localization';
|
||||
@@ -29,6 +29,7 @@ export const ActionsBar: React.FunctionComponent<IActionsBarProps> = ({
|
||||
const selectedFolder = useRecoilValue(SelectedMediaFolderSelector);
|
||||
const settings = useRecoilValue(SettingsSelector);
|
||||
const { files } = useFilesContext();
|
||||
const pagedItems = useRecoilValue(PagedItems);
|
||||
|
||||
const viewFile = React.useCallback(() => {
|
||||
if (selectedFiles.length === 1) {
|
||||
@@ -66,6 +67,10 @@ export const ActionsBar: React.FunctionComponent<IActionsBarProps> = ({
|
||||
}
|
||||
}, [selectedFiles]);
|
||||
|
||||
const selectAllItems = React.useCallback(() => {
|
||||
setSelectedFiles([...pagedItems]);
|
||||
}, [pagedItems]);
|
||||
|
||||
const languageActions = React.useMemo(() => {
|
||||
const actions: React.ReactNode[] = [];
|
||||
|
||||
@@ -192,6 +197,7 @@ export const ActionsBar: React.FunctionComponent<IActionsBarProps> = ({
|
||||
<ActionsBarItem
|
||||
disabled={selectedFiles.length === 0 || selectedFiles.length > 1}
|
||||
onClick={viewFile}
|
||||
title={l10n.t(LocalizationKey.commonView)}
|
||||
>
|
||||
<EyeIcon className="w-4 h-4 mr-2" aria-hidden="true" />
|
||||
<span>{l10n.t(LocalizationKey.commonView)}</span>
|
||||
@@ -205,6 +211,7 @@ export const ActionsBar: React.FunctionComponent<IActionsBarProps> = ({
|
||||
messageHandler.send(DashboardMessage.rename, selectedFiles[0]);
|
||||
setSelectedFiles([]);
|
||||
}}
|
||||
title={l10n.t(LocalizationKey.commonRename)}
|
||||
>
|
||||
<RenameIcon className="w-4 h-4 mr-2" aria-hidden="true" />
|
||||
<span>{l10n.t(LocalizationKey.commonRename)}</span>
|
||||
@@ -221,6 +228,7 @@ export const ActionsBar: React.FunctionComponent<IActionsBarProps> = ({
|
||||
path: selectedFiles[0],
|
||||
action: 'edit'
|
||||
})}
|
||||
title={l10n.t(LocalizationKey.commonEdit)}
|
||||
>
|
||||
<PencilIcon className="w-4 h-4 mr-2" aria-hidden="true" />
|
||||
<span>{l10n.t(LocalizationKey.commonEdit)}</span>
|
||||
@@ -237,25 +245,39 @@ export const ActionsBar: React.FunctionComponent<IActionsBarProps> = ({
|
||||
className='hover:text-[var(--vscode-statusBarItem-errorBackground)]'
|
||||
disabled={selectedFiles.length === 0}
|
||||
onClick={() => setShowAlert(true)}
|
||||
title={l10n.t(LocalizationKey.commonDelete)}
|
||||
>
|
||||
<TrashIcon className="w-4 h-4 mr-2" aria-hidden="true" />
|
||||
<span>{l10n.t(LocalizationKey.commonDelete)}</span>
|
||||
</ActionsBarItem>
|
||||
</div>
|
||||
|
||||
{
|
||||
selectedFiles.length > 0 && (
|
||||
<button
|
||||
type="button"
|
||||
className='flex items-center hover:text-[var(--vscode-statusBarItem-warningBackground)]'
|
||||
onClick={() => setSelectedFiles([])}
|
||||
>
|
||||
<XMarkIcon className="w-4 h-4 mr-1" aria-hidden="true" />
|
||||
<span>{l10n.t(LocalizationKey.dashboardHeaderActionsBarItemsSelected, selectedFiles.length)}</span>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<div className='flex gap-4'>
|
||||
{
|
||||
selectedFiles.length > 0 && (
|
||||
<ActionsBarItem
|
||||
className='flex items-center hover:text-[var(--vscode-statusBarItem-warningBackground)]'
|
||||
onClick={() => setSelectedFiles([])}
|
||||
title={l10n.t(LocalizationKey.dashboardHeaderActionsBarItemsSelected, selectedFiles.length)}
|
||||
>
|
||||
<XMarkIcon className="w-4 h-4 mr-1" aria-hidden="true" />
|
||||
<span>{l10n.t(LocalizationKey.dashboardHeaderActionsBarItemsSelected, selectedFiles.length)}</span>
|
||||
</ActionsBarItem>
|
||||
)
|
||||
}
|
||||
|
||||
<ActionsBarItem
|
||||
disabled={selectedFiles.length === pagedItems.length}
|
||||
onClick={selectAllItems}
|
||||
title={l10n.t(LocalizationKey.dashboardHeaderActionsBarSelectAll)}
|
||||
>
|
||||
<div className='w-4 h-4 inline-flex items-center justify-center border border-[var(--vscode-sideBar-foreground)] group-hover:border-[var(--vscode-statusBarItem-warningBackground)] rounded mr-1'>
|
||||
<CheckIcon className="w-3 h-3" aria-hidden="true" />
|
||||
</div>
|
||||
<span>{l10n.t(LocalizationKey.dashboardHeaderActionsBarSelectAll)}</span>
|
||||
</ActionsBarItem>
|
||||
</div>
|
||||
</div >
|
||||
|
||||
{showAlert && (
|
||||
<Alert
|
||||
@@ -266,7 +288,8 @@ export const ActionsBar: React.FunctionComponent<IActionsBarProps> = ({
|
||||
dismiss={() => setShowAlert(false)}
|
||||
trigger={onDeleteConfirm}
|
||||
/>
|
||||
)}
|
||||
)
|
||||
}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -2,6 +2,7 @@ import * as React from 'react';
|
||||
import { cn } from '../../../utils/cn';
|
||||
|
||||
export interface IActionsBarItemProps {
|
||||
title?: string;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
onClick?: () => void;
|
||||
@@ -11,11 +12,13 @@ export const ActionsBarItem: React.FunctionComponent<IActionsBarItemProps> = ({
|
||||
children,
|
||||
className,
|
||||
disabled,
|
||||
onClick
|
||||
onClick,
|
||||
title
|
||||
}: React.PropsWithChildren<IActionsBarItemProps>) => {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
title={title || ''}
|
||||
className={cn(`flex items-center text-[var(--vscode-tab-inactiveForeground)] hover:text-[var(--vscode-tab-activeForeground)] disabled:opacity-50 disabled:hover:text-[var(--vscode-tab-inactiveForeground)]`, className)}
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
|
||||
@@ -33,6 +33,9 @@ export const CustomActions: React.FunctionComponent<ICustomActionsProps> = ({
|
||||
));
|
||||
}, [scripts]);
|
||||
|
||||
if (!customActions.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (showTrigger) {
|
||||
return (
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Messenger } from '@estruyf/vscode/dist/client';
|
||||
import { ArrowUpTrayIcon } from '@heroicons/react/24/outline';
|
||||
import * as React from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import {
|
||||
LoadingAtom,
|
||||
MediaFoldersAtom,
|
||||
PagedItems,
|
||||
SelectedMediaFolderAtom,
|
||||
SettingsSelector,
|
||||
ViewDataSelector
|
||||
@@ -20,7 +21,7 @@ import { DashboardMessage } from '../../DashboardMessage';
|
||||
import { FrontMatterIcon } from '../../../panelWebView/components/Icons/FrontMatterIcon';
|
||||
import { FolderItem } from './FolderItem';
|
||||
import useMedia from '../../hooks/useMedia';
|
||||
import { GeneralCommands, STATIC_FOLDER_PLACEHOLDER, TelemetryEvent } from '../../../constants';
|
||||
import { STATIC_FOLDER_PLACEHOLDER, } from '../../../constants';
|
||||
import { PageLayout } from '../Layout/PageLayout';
|
||||
import { parseWinPath } from '../../../helpers/parseWinPath';
|
||||
import { basename, extname, join } from 'path';
|
||||
@@ -41,6 +42,7 @@ export const Media: React.FunctionComponent<IMediaProps> = (
|
||||
const selectedFolder = useRecoilValue(SelectedMediaFolderAtom);
|
||||
const folders = useRecoilValue(MediaFoldersAtom);
|
||||
const loading = useRecoilValue(LoadingAtom);
|
||||
const [, setPagedItems] = useRecoilState(PagedItems);
|
||||
|
||||
const currentStaticFolder = useMemo(() => {
|
||||
if (settings?.staticFolder) {
|
||||
@@ -126,6 +128,7 @@ export const Media: React.FunctionComponent<IMediaProps> = (
|
||||
});
|
||||
}
|
||||
|
||||
setPagedItems(mediaFiles.map((m) => m.fsPath));
|
||||
return mediaFiles;
|
||||
}, [media, viewData, currentStaticFolder, settings?.staticFolder]);
|
||||
|
||||
@@ -151,15 +154,6 @@ export const Media: React.FunctionComponent<IMediaProps> = (
|
||||
|
||||
useEffect(() => {
|
||||
Messenger.send(DashboardMessage.setTitle, l10n.t(LocalizationKey.dashboardHeaderTabsMedia));
|
||||
|
||||
Messenger.send(DashboardMessage.sendTelemetry, {
|
||||
event: TelemetryEvent.webviewMediaView
|
||||
});
|
||||
|
||||
Messenger.send(GeneralCommands.toVSCode.logging.info, {
|
||||
message: `Media view loaded`,
|
||||
location: 'DASHBOARD'
|
||||
});
|
||||
}, []);
|
||||
|
||||
const { getRootProps, isDragActive } = useDropzone({
|
||||
|
||||
@@ -8,7 +8,7 @@ import { AstroContentTypes } from '../Configuration/Astro/AstroContentTypes';
|
||||
import { ContentFolders } from '../Configuration/Common/ContentFolders';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../../localization';
|
||||
import { COMMAND_NAME, TelemetryEvent } from '../../../constants';
|
||||
import { COMMAND_NAME } from '../../../constants';
|
||||
import { ArrowPathIcon } from '@heroicons/react/24/outline';
|
||||
import { VSCodePanelTab, VSCodePanelView, VSCodePanels } from '@vscode/webview-ui-toolkit/react';
|
||||
import { CommonSettings } from './CommonSettings';
|
||||
@@ -25,10 +25,6 @@ export const SettingsView: React.FunctionComponent<ISettingsViewProps> = (_: Rea
|
||||
|
||||
useEffect(() => {
|
||||
Messenger.send(DashboardMessage.setTitle, l10n.t(LocalizationKey.commonSettings));
|
||||
|
||||
Messenger.send(DashboardMessage.sendTelemetry, {
|
||||
event: TelemetryEvent.webviewSettings
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
@@ -5,7 +5,6 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { FeatureFlag } from '../../../components/features/FeatureFlag';
|
||||
import { FEATURE_FLAG, GeneralCommands, WEBSITE_LINKS } from '../../../constants';
|
||||
import { TelemetryEvent } from '../../../constants/TelemetryEvent';
|
||||
import { SnippetParser } from '../../../helpers/SnippetParser';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
import { ModeAtom, SettingsSelector, ViewDataSelector } from '../../state';
|
||||
@@ -84,10 +83,6 @@ export const Snippets: React.FunctionComponent<ISnippetsProps> = (
|
||||
useEffect(() => {
|
||||
Messenger.send(DashboardMessage.setTitle, l10n.t(LocalizationKey.dashboardHeaderTabsSnippets));
|
||||
|
||||
Messenger.send(DashboardMessage.sendTelemetry, {
|
||||
event: TelemetryEvent.webviewSnippetsView
|
||||
});
|
||||
|
||||
Messenger.send(GeneralCommands.toVSCode.logging.info, {
|
||||
message: `Snippets view loaded`,
|
||||
location: 'DASHBOARD'
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ChevronRightIcon, ArrowDownTrayIcon } from '@heroicons/react/24/outline
|
||||
import * as React from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { GeneralCommands, TelemetryEvent } from '../../../constants';
|
||||
import { GeneralCommands } from '../../../constants';
|
||||
import { TaxonomyData } from '../../../models';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
import { Page, PageMappings } from '../../models';
|
||||
@@ -55,10 +55,6 @@ export const TaxonomyView: React.FunctionComponent<ITaxonomyViewProps> = ({
|
||||
useEffect(() => {
|
||||
Messenger.send(DashboardMessage.setTitle, l10n.t(LocalizationKey.dashboardHeaderTabsTaxonomies));
|
||||
|
||||
Messenger.send(DashboardMessage.sendTelemetry, {
|
||||
event: TelemetryEvent.webviewTaxonomyDashboard
|
||||
});
|
||||
|
||||
Messenger.send(GeneralCommands.toVSCode.logging.info, {
|
||||
message: 'Taxonomy view loaded',
|
||||
location: 'DASHBOARD'
|
||||
|
||||
@@ -5,7 +5,6 @@ import { LocalizationKey } from '../../../localization';
|
||||
import { useEffect } from 'react';
|
||||
import { Messenger } from '@estruyf/vscode/dist/client';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
import { TelemetryEvent } from '../../../constants';
|
||||
|
||||
export interface IUnknownViewProps { }
|
||||
|
||||
@@ -14,10 +13,6 @@ export const UnknownView: React.FunctionComponent<IUnknownViewProps> = (
|
||||
) => {
|
||||
useEffect(() => {
|
||||
Messenger.send(DashboardMessage.setTitle, "Unknown View");
|
||||
|
||||
Messenger.send(DashboardMessage.sendTelemetry, {
|
||||
event: TelemetryEvent.webviewUnknown
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { BookOpenIcon, HeartIcon, StarIcon } from '@heroicons/react/24/outline';
|
||||
import * as React from 'react';
|
||||
import { DOCUMENTATION_LINK, GITHUB_LINK, GeneralCommands, REVIEW_LINK, SPONSOR_LINK, TelemetryEvent } from '../../../constants';
|
||||
import { DOCUMENTATION_LINK, GITHUB_LINK, GeneralCommands, REVIEW_LINK, SPONSOR_LINK } from '../../../constants';
|
||||
import { Messenger } from '@estruyf/vscode/dist/client';
|
||||
import { FrontMatterIcon } from '../../../panelWebView/components/Icons/FrontMatterIcon';
|
||||
import { GitHubIcon } from '../../../panelWebView/components/Icons/GitHubIcon';
|
||||
@@ -25,9 +25,6 @@ export const WelcomeScreen: React.FunctionComponent<IWelcomeScreenProps> = ({
|
||||
|
||||
React.useEffect(() => {
|
||||
setView(NavigationType.Welcome);
|
||||
Messenger.send(DashboardMessage.sendTelemetry, {
|
||||
event: TelemetryEvent.webviewWelcomeScreen
|
||||
});
|
||||
|
||||
Messenger.send(GeneralCommands.toVSCode.logging.info, {
|
||||
message: 'Welcome screen loaded',
|
||||
|
||||
@@ -93,7 +93,7 @@ if (elm) {
|
||||
render(
|
||||
<I10nProvider>
|
||||
<SettingsProvider
|
||||
aiUrl={WEBSITE_LINKS.root}
|
||||
aiUrl={WEBSITE_LINKS.api.baseUrl}
|
||||
experimental={experimental === 'true'}
|
||||
version={version || ""}>
|
||||
<Chatbot />
|
||||
|
||||
6
src/dashboardWebView/state/atom/PagedItems.ts
Normal file
6
src/dashboardWebView/state/atom/PagedItems.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
export const PagedItems = atom<string[]>({
|
||||
key: 'PagedItems',
|
||||
default: []
|
||||
});
|
||||
@@ -16,6 +16,7 @@ export * from './MediaTotalAtom';
|
||||
export * from './ModeAtom';
|
||||
export * from './MultiSelectedItemsAtom';
|
||||
export * from './PageAtom';
|
||||
export * from './PagedItems';
|
||||
export * from './PinnedItems';
|
||||
export * from './SearchAtom';
|
||||
export * from './SearchReadyAtom';
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { GitListener } from './listeners/general/GitListener';
|
||||
import * as vscode from 'vscode';
|
||||
import { COMMAND_NAME, CONTEXT, EXTENSION_NAME, TelemetryEvent } from './constants';
|
||||
import { COMMAND_NAME, CONTEXT, EXTENSION_NAME } from './constants';
|
||||
import { MarkdownFoldingProvider } from './providers/MarkdownFoldingProvider';
|
||||
import { TagType } from './panelWebView/TagType';
|
||||
import { PanelProvider } from './panelWebView/PanelProvider';
|
||||
import {
|
||||
DashboardSettings,
|
||||
@@ -31,11 +30,13 @@ import {
|
||||
Article,
|
||||
Settings,
|
||||
StatusListener,
|
||||
Chatbot
|
||||
Chatbot,
|
||||
Taxonomy
|
||||
} from './commands';
|
||||
import { join } from 'path';
|
||||
import { Terminal } from './services';
|
||||
import { i18n } from './commands/i18n';
|
||||
import { UriHandler } from './providers/UriHandler';
|
||||
|
||||
let pageUpdateDebouncer: { (fnc: any, time: number): void };
|
||||
let editDebounce: { (fnc: any, time: number): void };
|
||||
@@ -54,6 +55,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
vscode.commands.executeCommand('setContext', CONTEXT.isDevelopment, true);
|
||||
}
|
||||
|
||||
// Sponsor check
|
||||
Backers.init(context).then(() => {});
|
||||
|
||||
// Make sure the EN language file is loaded
|
||||
@@ -79,9 +81,6 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
SettingsHelper.checkToPromote();
|
||||
|
||||
// Sends the activation event
|
||||
Telemetry.send(TelemetryEvent.activate);
|
||||
|
||||
// Start listening to the folders for content changes.
|
||||
// This will make sure the dashboard is up to date
|
||||
PagesListener.startWatchers();
|
||||
@@ -118,32 +117,16 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
// Folding the front matter of markdown files
|
||||
MarkdownFoldingProvider.register();
|
||||
|
||||
const insertTags = vscode.commands.registerCommand(COMMAND_NAME.insertTags, async () => {
|
||||
await vscode.commands.executeCommand('workbench.view.extension.frontmatter-explorer');
|
||||
await vscode.commands.executeCommand('workbench.action.focusSideBar');
|
||||
explorerSidebar.triggerInputFocus(TagType.tags);
|
||||
});
|
||||
|
||||
const insertCategories = vscode.commands.registerCommand(
|
||||
COMMAND_NAME.insertCategories,
|
||||
async () => {
|
||||
await vscode.commands.executeCommand('workbench.view.extension.frontmatter-explorer');
|
||||
await vscode.commands.executeCommand('workbench.action.focusSideBar');
|
||||
explorerSidebar.triggerInputFocus(TagType.categories);
|
||||
}
|
||||
);
|
||||
// Register the taxonomy commands
|
||||
Taxonomy.registerCommands(subscriptions);
|
||||
|
||||
// Register all the article commands
|
||||
Article.registerCommands(subscriptions);
|
||||
|
||||
/**
|
||||
* Template creation
|
||||
*/
|
||||
// Template creation
|
||||
Template.registerCommands();
|
||||
|
||||
/**
|
||||
* Content creation
|
||||
*/
|
||||
// Content creation
|
||||
ContentType.registerCommands();
|
||||
Content.registerCommands();
|
||||
Folders.registerCommands();
|
||||
@@ -251,8 +234,11 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
// Cache commands
|
||||
Cache.registerCommands();
|
||||
|
||||
// Register the URI handler
|
||||
UriHandler.register();
|
||||
|
||||
// Subscribe all commands
|
||||
subscriptions.push(insertTags, PanelView, insertCategories, collapseAll, fmStatusBarItem);
|
||||
subscriptions.push(PanelView, collapseAll, fmStatusBarItem);
|
||||
|
||||
console.log(`𝖥𝗋𝗈𝗇𝗍 𝖬𝖺𝗍𝗍𝖾𝗋 𝖢𝖬𝖲 𝖺𝖼𝗍𝗂𝗏𝖺𝗍𝖾𝖽! 𝖱𝖾𝖺𝖽𝗒 𝗍𝗈 𝗌𝗍𝖺𝗋𝗍 𝗐𝗋𝗂𝗍𝗂𝗇𝗀... 👩💻🧑💻👨💻`);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ import { Link, Parent } from 'mdast-util-from-markdown/lib';
|
||||
import { Content } from 'mdast';
|
||||
import { CustomScript } from './CustomScript';
|
||||
import { Folders } from '../commands/Folders';
|
||||
import { existsAsync } from '../utils';
|
||||
import { existsAsync, getTitleField } from '../utils';
|
||||
import { mkdirAsync } from '../utils/mkdirAsync';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
@@ -460,8 +460,10 @@ export class ArticleHelper {
|
||||
let contentType: IContentType | undefined = undefined;
|
||||
|
||||
// Get content type by type name in the front matter
|
||||
if (article.data.type) {
|
||||
contentType = contentTypes.find((ct) => ct.name === article.data.type);
|
||||
if (article.data[DefaultFields.ContentType]) {
|
||||
contentType = contentTypes.find((ct) => ct.name === article.data[DefaultFields.ContentType]);
|
||||
} else if (article.data[DefaultFields.Type]) {
|
||||
contentType = contentTypes.find((ct) => ct.name === article.data[DefaultFields.Type]);
|
||||
} else if (!contentType && article.path) {
|
||||
const pageFolder = await Folders.getPageFolderByFilePath(article.path);
|
||||
if (pageFolder && pageFolder.contentTypes?.length === 1) {
|
||||
@@ -635,11 +637,12 @@ export class ArticleHelper {
|
||||
) {
|
||||
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
||||
const fmData = Object.assign({}, data);
|
||||
const titleField = getTitleField();
|
||||
|
||||
for (const fieldName of Object.keys(fmData)) {
|
||||
const fieldValue = fmData[fieldName];
|
||||
|
||||
if (fieldName === 'title' && (fieldValue === null || fieldValue === '')) {
|
||||
if (fieldName === titleField && (fieldValue === null || fieldValue === '')) {
|
||||
fmData[fieldName] = title;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,14 +12,14 @@ import {
|
||||
import {
|
||||
COMMAND_NAME,
|
||||
DefaultFieldValues,
|
||||
DefaultFields,
|
||||
EXTENSION_NAME,
|
||||
FEATURE_FLAG,
|
||||
SETTING_CONTENT_DRAFT_FIELD,
|
||||
SETTING_DATE_FORMAT,
|
||||
SETTING_FRAMEWORK_ID,
|
||||
SETTING_TAXONOMY_CONTENT_TYPES,
|
||||
SETTING_TAXONOMY_FIELD_GROUPS,
|
||||
TelemetryEvent
|
||||
SETTING_TAXONOMY_FIELD_GROUPS
|
||||
} from '../constants';
|
||||
import {
|
||||
ContentType as IContentType,
|
||||
@@ -37,7 +37,7 @@ import { DEFAULT_CONTENT_TYPE_NAME } from '../constants/ContentType';
|
||||
import { Telemetry } from './Telemetry';
|
||||
import { basename } from 'path';
|
||||
import { ParsedFrontMatter } from '../parsers';
|
||||
import { encodeEmoji, existsAsync, fieldWhenClause, writeFileAsync } from '../utils';
|
||||
import { encodeEmoji, existsAsync, fieldWhenClause, getTitleField, writeFileAsync } from '../utils';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
@@ -185,7 +185,7 @@ export class ContentType {
|
||||
fields.splice(fieldIdx, 1, ...fieldGroup.fields);
|
||||
}
|
||||
} else if (field && field.type === 'fields') {
|
||||
fields = field.fields || [];
|
||||
field.fields = field.fields || [];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -203,8 +203,6 @@ export class ContentType {
|
||||
return;
|
||||
}
|
||||
|
||||
Telemetry.send(TelemetryEvent.generateContentType);
|
||||
|
||||
const content = ArticleHelper.getCurrent();
|
||||
|
||||
const editor = window.activeTextEditor;
|
||||
@@ -284,7 +282,7 @@ export class ContentType {
|
||||
|
||||
// Update the type field in the page
|
||||
if (!overrideBool && editor) {
|
||||
content.data['type'] = contentTypeName;
|
||||
content.data[DefaultFields.ContentType] = contentTypeName;
|
||||
ArticleHelper.update(editor, content);
|
||||
}
|
||||
|
||||
@@ -332,8 +330,6 @@ export class ContentType {
|
||||
return;
|
||||
}
|
||||
|
||||
Telemetry.send(TelemetryEvent.addMissingFields);
|
||||
|
||||
const article = ArticleHelper.getCurrent();
|
||||
|
||||
if (!article || !article.data) {
|
||||
@@ -377,8 +373,6 @@ export class ContentType {
|
||||
return;
|
||||
}
|
||||
|
||||
Telemetry.send(TelemetryEvent.setContentType);
|
||||
|
||||
const content = ArticleHelper.getCurrent();
|
||||
const contentTypes = ContentType.getAll() || [];
|
||||
|
||||
@@ -402,7 +396,7 @@ export class ContentType {
|
||||
return;
|
||||
}
|
||||
|
||||
content.data.type = ctAnswer;
|
||||
content.data[DefaultFields.ContentType] = ctAnswer;
|
||||
|
||||
const editor = window.activeTextEditor;
|
||||
ArticleHelper.update(editor!, content);
|
||||
@@ -950,8 +944,11 @@ export class ContentType {
|
||||
}
|
||||
|
||||
titleValue = titleValue.trim();
|
||||
|
||||
const titleFieldName = getTitleField();
|
||||
|
||||
// Check if the title needs to encode the emoji's used in it
|
||||
const titleField = contentType.fields.find((f) => f.name === 'title');
|
||||
const titleField = contentType.fields.find((f) => f.name === titleFieldName);
|
||||
if (titleField && titleField.encodeEmoji) {
|
||||
titleValue = encodeEmoji(titleValue);
|
||||
}
|
||||
@@ -991,12 +988,8 @@ export class ContentType {
|
||||
contentType
|
||||
);
|
||||
|
||||
let isTypeSet = false;
|
||||
if (data.type) {
|
||||
isTypeSet = true;
|
||||
} else {
|
||||
data.type = contentType.name;
|
||||
}
|
||||
// Set the content type
|
||||
data[DefaultFields.ContentType] = contentType.name;
|
||||
|
||||
const article: ParsedFrontMatter = {
|
||||
content: '',
|
||||
@@ -1006,12 +999,11 @@ export class ContentType {
|
||||
|
||||
data = await ArticleHelper.updateDates(article);
|
||||
|
||||
if (isTypeSet) {
|
||||
delete data.type;
|
||||
}
|
||||
|
||||
if (contentType.name !== DEFAULT_CONTENT_TYPE_NAME) {
|
||||
data['type'] = contentType.name;
|
||||
data[DefaultFields.ContentType] = contentType.name;
|
||||
} else {
|
||||
// Default content type, remove the content type field
|
||||
delete data[DefaultFields.ContentType];
|
||||
}
|
||||
|
||||
const content = ArticleHelper.stringifyFrontMatter(templateData?.content || ``, data);
|
||||
@@ -1035,8 +1027,6 @@ export class ContentType {
|
||||
|
||||
Notifications.info(l10n.t(LocalizationKey.helpersContentTypeCreateSuccess));
|
||||
|
||||
Telemetry.send(TelemetryEvent.createContentFromContentType);
|
||||
|
||||
// Trigger a refresh for the dashboard
|
||||
PagesListener.refresh();
|
||||
}
|
||||
@@ -1058,6 +1048,7 @@ export class ContentType {
|
||||
isRoot: boolean = true
|
||||
): Promise<any> {
|
||||
if (obj.fields) {
|
||||
const titleField = getTitleField();
|
||||
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
|
||||
|
||||
for (const field of obj.fields) {
|
||||
@@ -1066,7 +1057,7 @@ export class ContentType {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (field.name === 'title') {
|
||||
if (field.name === titleField) {
|
||||
if (field.default) {
|
||||
data[field.name] = processArticlePlaceholdersFromData(
|
||||
field.default as string,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Settings } from './SettingsHelper';
|
||||
import { CommandType, EnvironmentType } from './../models/PanelSettings';
|
||||
import { CustomScript as ICustomScript, ScriptType } from '../models/PanelSettings';
|
||||
import { window, env as vscodeEnv, ProgressLocation, Uri, commands } from 'vscode';
|
||||
import { ArticleHelper, Logger, MediaHelpers, Telemetry } from '.';
|
||||
import { ArticleHelper, Logger, MediaHelpers } from '.';
|
||||
import { Folders, WORKSPACE_PLACEHOLDER } from '../commands/Folders';
|
||||
import { exec, execSync } from 'child_process';
|
||||
import * as os from 'os';
|
||||
@@ -12,7 +12,6 @@ import ContentProvider from '../providers/ContentProvider';
|
||||
import { Dashboard } from '../commands/Dashboard';
|
||||
import { DashboardCommand } from '../dashboardWebView/DashboardCommand';
|
||||
import { ParsedFrontMatter } from '../parsers';
|
||||
import { TelemetryEvent } from '../constants/TelemetryEvent';
|
||||
import { SETTING_CUSTOM_SCRIPTS } from '../constants';
|
||||
import { existsAsync } from '../utils';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
@@ -40,12 +39,8 @@ export class CustomScript {
|
||||
const wsPath = wsFolder.fsPath;
|
||||
|
||||
if (script.type === ScriptType.MediaFile || script.type === ScriptType.MediaFolder) {
|
||||
Telemetry.send(TelemetryEvent.runMediaScript);
|
||||
|
||||
await CustomScript.runMediaScript(wsPath, path, script);
|
||||
} else {
|
||||
Telemetry.send(TelemetryEvent.runCustomScript);
|
||||
|
||||
if (script.bulk) {
|
||||
// Run script on all files
|
||||
await CustomScript.bulkRun(wsPath, script);
|
||||
@@ -67,11 +62,11 @@ export class CustomScript {
|
||||
* @param path
|
||||
* @returns
|
||||
*/
|
||||
private static async singleRun(
|
||||
public static async singleRun(
|
||||
wsPath: string,
|
||||
script: ICustomScript,
|
||||
path: string | null = null
|
||||
): Promise<void> {
|
||||
): Promise<any> {
|
||||
let articlePath: string | null = path;
|
||||
let article: ParsedFrontMatter | null | undefined = null;
|
||||
|
||||
@@ -99,7 +94,7 @@ export class CustomScript {
|
||||
articlePath as string,
|
||||
script
|
||||
);
|
||||
await CustomScript.showOutput(output, script, articlePath);
|
||||
return await CustomScript.showOutput(output, script, articlePath);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
@@ -133,7 +128,7 @@ export class CustomScript {
|
||||
title: l10n.t(LocalizationKey.helpersCustomScriptExecuting, script.title),
|
||||
cancellable: false
|
||||
},
|
||||
async (progress, token) => {
|
||||
async (_, __) => {
|
||||
for await (const folder of folders) {
|
||||
if (folder.lastModified.length > 0) {
|
||||
for await (const file of folder.lastModified) {
|
||||
@@ -266,15 +261,21 @@ export class CustomScript {
|
||||
output: string | null,
|
||||
script: ICustomScript,
|
||||
articlePath?: string | null
|
||||
): Promise<void> {
|
||||
): Promise<any> {
|
||||
if (output) {
|
||||
try {
|
||||
const data: {
|
||||
frontmatter?: { [key: string]: any };
|
||||
fmAction?: 'open' | 'copyMediaMetadata' | 'copyMediaMetadataAndDelete' | 'deleteMedia';
|
||||
fmAction?:
|
||||
| 'open'
|
||||
| 'copyMediaMetadata'
|
||||
| 'copyMediaMetadataAndDelete'
|
||||
| 'deleteMedia'
|
||||
| 'fieldAction';
|
||||
fmPath?: string;
|
||||
fmSourcePath?: string;
|
||||
fmDestinationPath?: string;
|
||||
fmFieldValue?: any;
|
||||
} = JSON.parse(output);
|
||||
|
||||
if (data.frontmatter) {
|
||||
@@ -326,6 +327,8 @@ export class CustomScript {
|
||||
await MediaHelpers.deleteFile(data.fmSourcePath);
|
||||
} else if (data.fmAction === 'deleteMedia' && data.fmPath) {
|
||||
await MediaHelpers.deleteFile(data.fmPath);
|
||||
} else if (data.fmAction === 'fieldAction') {
|
||||
return data.fmFieldValue || undefined;
|
||||
}
|
||||
} else {
|
||||
Logger.error(`No frontmatter found.`);
|
||||
|
||||
@@ -10,7 +10,6 @@ import { Preview } from '../commands/Preview';
|
||||
import { Project } from '../commands/Project';
|
||||
import {
|
||||
CONTEXT,
|
||||
DefaultFields,
|
||||
SETTING_CONTENT_DRAFT_FIELD,
|
||||
SETTING_CONTENT_FRONTMATTER_HIGHLIGHT,
|
||||
SETTING_DATA_TYPES,
|
||||
@@ -22,7 +21,6 @@ import {
|
||||
SETTING_DATE_FORMAT,
|
||||
SETTING_PANEL_FREEFORM,
|
||||
SETTING_SEO_CONTENT_MIN_LENGTH,
|
||||
SETTING_SEO_DESCRIPTION_FIELD,
|
||||
SETTING_SEO_DESCRIPTION_LENGTH,
|
||||
SETTING_SEO_SLUG_LENGTH,
|
||||
SETTING_SEO_TITLE_LENGTH,
|
||||
@@ -30,8 +28,7 @@ import {
|
||||
SETTING_SLUG_SUFFIX,
|
||||
SETTING_SLUG_UPDATE_FILE_NAME,
|
||||
SETTING_TAXONOMY_CUSTOM,
|
||||
SETTING_TAXONOMY_FIELD_GROUPS,
|
||||
SETTING_SEO_TITLE_FIELD
|
||||
SETTING_TAXONOMY_FIELD_GROUPS
|
||||
} from '../constants';
|
||||
import { GitListener } from '../listeners/general';
|
||||
import {
|
||||
@@ -46,6 +43,7 @@ import {
|
||||
} from '../models';
|
||||
import { Folders } from '../commands';
|
||||
import { Copilot } from '../services/Copilot';
|
||||
import { getDescriptionField, getTitleField } from '../utils';
|
||||
|
||||
export class PanelSettings {
|
||||
public static async get(): Promise<IPanelSettings> {
|
||||
@@ -61,9 +59,8 @@ export class PanelSettings {
|
||||
slug: (Settings.get(SETTING_SEO_SLUG_LENGTH) as number) || -1,
|
||||
description: (Settings.get(SETTING_SEO_DESCRIPTION_LENGTH) as number) || -1,
|
||||
content: (Settings.get(SETTING_SEO_CONTENT_MIN_LENGTH) as number) || -1,
|
||||
titleField: (Settings.get(SETTING_SEO_TITLE_FIELD) as string) || DefaultFields.Title,
|
||||
descriptionField:
|
||||
(Settings.get(SETTING_SEO_DESCRIPTION_FIELD) as string) || DefaultFields.Description
|
||||
titleField: getTitleField(),
|
||||
descriptionField: getDescriptionField()
|
||||
},
|
||||
slug: {
|
||||
prefix: Settings.get(SETTING_SLUG_PREFIX) || '',
|
||||
|
||||
@@ -241,7 +241,7 @@ export class Questions {
|
||||
|
||||
if (options.length === 0) {
|
||||
Notifications.error(
|
||||
LocalizationKey.helpersQuestionsSelectContentTypeQuickPickErrorNoContentTypes
|
||||
l10n.t(LocalizationKey.helpersQuestionsSelectContentTypeQuickPickErrorNoContentTypes)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { parseWinPath } from './parseWinPath';
|
||||
import { Telemetry } from './Telemetry';
|
||||
import { Notifications } from './Notifications';
|
||||
import {
|
||||
commands,
|
||||
@@ -18,7 +17,6 @@ import {
|
||||
CONTEXT,
|
||||
ExtensionState,
|
||||
SETTING_TAXONOMY_CUSTOM,
|
||||
TelemetryEvent,
|
||||
COMMAND_NAME,
|
||||
SETTING_TAXONOMY_CONTENT_TYPES,
|
||||
SETTING_CONTENT_PAGE_FOLDERS,
|
||||
@@ -516,7 +514,9 @@ ${JSON.stringify(value, null, 2)}`,
|
||||
}frontmatter.codes/frontmatter.schema.json`
|
||||
};
|
||||
|
||||
if (wsFolder) {
|
||||
const projectFile = await Settings.projectConfigPath();
|
||||
|
||||
if (wsFolder && !projectFile) {
|
||||
const configPath = join(wsFolder.fsPath, Settings.globalFile);
|
||||
if (!(await existsAsync(configPath))) {
|
||||
await writeFileAsync(configPath, JSON.stringify(initialConfig, null, 2), 'utf8');
|
||||
@@ -600,8 +600,6 @@ ${JSON.stringify(value, null, 2)}`,
|
||||
}
|
||||
|
||||
Notifications.info(l10n.t(LocalizationKey.helpersSettingsHelperPromoteSuccess));
|
||||
|
||||
Telemetry.send(TelemetryEvent.promoteSettings);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,32 +1,6 @@
|
||||
import { workspace } from 'vscode';
|
||||
import { Extension, Settings } from '.';
|
||||
import {
|
||||
EXTENSION_BETA_ID,
|
||||
EXTENSION_ID,
|
||||
SETTING_TELEMETRY_DISABLE,
|
||||
WEBSITE_LINKS
|
||||
} from '../constants';
|
||||
|
||||
export class Telemetry {
|
||||
private static instance: Telemetry;
|
||||
private extTitle: string;
|
||||
private extVersion: string;
|
||||
private events: any[] = [];
|
||||
private timeout: NodeJS.Timeout | undefined;
|
||||
|
||||
private constructor() {
|
||||
const extension = Extension.getInstance();
|
||||
this.extTitle = extension.isBetaVersion() ? EXTENSION_BETA_ID : EXTENSION_ID;
|
||||
this.extVersion = extension.version;
|
||||
}
|
||||
|
||||
public static getInstance(): Telemetry {
|
||||
if (!Telemetry.instance) {
|
||||
Telemetry.instance = new Telemetry();
|
||||
}
|
||||
return Telemetry.instance;
|
||||
}
|
||||
|
||||
public static isVscodeEnabled(): boolean {
|
||||
const config = workspace.getConfiguration('telemetry');
|
||||
const isVscodeEnable = config.get<'off' | undefined>('enableTelemetry');
|
||||
@@ -39,56 +13,6 @@ export class Telemetry {
|
||||
*/
|
||||
public static isEnabled(): boolean {
|
||||
const isVscodeEnable = Telemetry.isVscodeEnabled();
|
||||
|
||||
const isDisabled = Settings.get<boolean>(SETTING_TELEMETRY_DISABLE);
|
||||
|
||||
return isDisabled || isVscodeEnable ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send metrics to our own database
|
||||
* @param eventName
|
||||
* @param properties
|
||||
* @returns
|
||||
*/
|
||||
public static send(eventName: string, properties?: any) {
|
||||
if (!Telemetry.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const instance = Telemetry.getInstance();
|
||||
instance.events.push({
|
||||
name: eventName,
|
||||
extName: instance.extTitle,
|
||||
version: instance.extVersion,
|
||||
properties
|
||||
});
|
||||
|
||||
instance.debounceMetrics();
|
||||
}
|
||||
|
||||
/**
|
||||
* Debounce the metrics by 1 second
|
||||
*/
|
||||
private async debounceMetrics() {
|
||||
const instance = Telemetry.getInstance();
|
||||
|
||||
// Check if timeout was defined
|
||||
if (instance.timeout) {
|
||||
clearTimeout(instance.timeout);
|
||||
}
|
||||
|
||||
// Set a new timeout
|
||||
instance.timeout = setTimeout(async () => {
|
||||
await fetch(WEBSITE_LINKS.api.metrics, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(this.events)
|
||||
});
|
||||
// Reset the events
|
||||
this.events = [];
|
||||
}, 1000) as any as NodeJS.Timeout;
|
||||
return isVscodeEnable ? false : true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ContentType } from '../models';
|
||||
import { getTitleField } from '../utils';
|
||||
import { ArticleHelper } from './ArticleHelper';
|
||||
import { SlugHelper } from './SlugHelper';
|
||||
|
||||
@@ -7,16 +8,17 @@ export const processArticlePlaceholdersFromData = (
|
||||
data: { [key: string]: any },
|
||||
contentType: ContentType
|
||||
): string => {
|
||||
if (value.includes('{{title}}') && data.title) {
|
||||
const titleField = getTitleField();
|
||||
if (value.includes('{{title}}') && data[titleField]) {
|
||||
const regex = new RegExp('{{title}}', 'g');
|
||||
value = value.replace(regex, data.title || '');
|
||||
value = value.replace(regex, data[titleField] || '');
|
||||
}
|
||||
|
||||
if (value.includes('{{slug}}')) {
|
||||
const regex = new RegExp('{{slug}}', 'g');
|
||||
value = value.replace(
|
||||
regex,
|
||||
SlugHelper.createSlug(data.title || '', data, contentType.slugTemplate) || ''
|
||||
SlugHelper.createSlug(data[titleField] || '', data, contentType.slugTemplate) || ''
|
||||
);
|
||||
}
|
||||
|
||||
@@ -32,9 +34,11 @@ export const processArticlePlaceholdersFromPath = async (
|
||||
return value;
|
||||
}
|
||||
|
||||
const titleField = getTitleField();
|
||||
|
||||
if (value.includes('{{title}}')) {
|
||||
const regex = new RegExp('{{title}}', 'g');
|
||||
value = value.replace(regex, article.data.title || '');
|
||||
value = value.replace(regex, article.data[titleField] || '');
|
||||
}
|
||||
|
||||
if (value.includes('{{slug}}') && filePath) {
|
||||
@@ -43,8 +47,11 @@ export const processArticlePlaceholdersFromPath = async (
|
||||
const regex = new RegExp('{{slug}}', 'g');
|
||||
value = value.replace(
|
||||
regex,
|
||||
SlugHelper.createSlug(article.data.title || '', article.data, contentType.slugTemplate) ||
|
||||
''
|
||||
SlugHelper.createSlug(
|
||||
article.data[titleField] || '',
|
||||
article.data,
|
||||
contentType.slugTemplate
|
||||
) || ''
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useState, useEffect } from 'react';
|
||||
import { DEFAULT_CONTENT_TYPE, DEFAULT_CONTENT_TYPE_NAME } from '../constants/ContentType';
|
||||
import { Settings } from '../dashboardWebView/models';
|
||||
import { ContentType, PanelSettings } from '../models';
|
||||
import { DefaultFields } from '../constants';
|
||||
|
||||
export default function useContentType(
|
||||
settings: PanelSettings | Settings | undefined | null,
|
||||
@@ -13,8 +14,12 @@ export default function useContentType(
|
||||
if (settings && metadata) {
|
||||
let contentTypeName = DEFAULT_CONTENT_TYPE_NAME;
|
||||
|
||||
if (metadata?.type) {
|
||||
contentTypeName = metadata.type;
|
||||
if (metadata) {
|
||||
if (metadata[DefaultFields.ContentType]) {
|
||||
contentTypeName = metadata[DefaultFields.ContentType];
|
||||
} else if (metadata[DefaultFields.Type]) {
|
||||
contentTypeName = metadata[DefaultFields.Type];
|
||||
}
|
||||
}
|
||||
|
||||
// Get the content type by the folder name
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { Telemetry } from '../../helpers/Telemetry';
|
||||
import { MediaHelpers } from '../../helpers/MediaHelpers';
|
||||
import { DashboardMessage } from '../../dashboardWebView/DashboardMessage';
|
||||
import { BaseListener } from './BaseListener';
|
||||
import { DashboardCommand } from '../../dashboardWebView/DashboardCommand';
|
||||
import { SortingOption } from '../../dashboardWebView/models';
|
||||
import { commands, env, Uri } from 'vscode';
|
||||
import { COMMAND_NAME, TelemetryEvent } from '../../constants';
|
||||
import { COMMAND_NAME } from '../../constants';
|
||||
import * as os from 'os';
|
||||
import { Folders } from '../../commands';
|
||||
import { PostMessageData, UnmappedMedia } from '../../models';
|
||||
@@ -24,31 +23,25 @@ export class MediaListener extends BaseListener {
|
||||
this.sendMediaFiles(page, folder, sorting);
|
||||
break;
|
||||
case DashboardMessage.refreshMedia:
|
||||
Telemetry.send(TelemetryEvent.refreshMedia);
|
||||
MediaHelpers.resetMedia();
|
||||
this.sendMediaFiles(0, msg?.payload?.folder);
|
||||
break;
|
||||
case DashboardMessage.uploadMedia:
|
||||
Telemetry.send(TelemetryEvent.uploadMedia);
|
||||
this.store(msg?.payload);
|
||||
break;
|
||||
case DashboardMessage.deleteMedia:
|
||||
Telemetry.send(TelemetryEvent.deleteMedia);
|
||||
this.delete(msg?.payload);
|
||||
break;
|
||||
case DashboardMessage.revealMedia:
|
||||
this.openFileInFinder(msg?.payload?.file);
|
||||
break;
|
||||
case DashboardMessage.insertMedia:
|
||||
Telemetry.send(TelemetryEvent.insertMediaToContent);
|
||||
MediaHelpers.insertMediaToMarkdown(msg?.payload);
|
||||
break;
|
||||
case DashboardMessage.insertFile:
|
||||
Telemetry.send(TelemetryEvent.insertFileToContent);
|
||||
MediaHelpers.insertMediaToMarkdown(msg?.payload);
|
||||
break;
|
||||
case DashboardMessage.updateMediaMetadata:
|
||||
Telemetry.send(TelemetryEvent.updateMediaMetadata);
|
||||
this.update(msg.payload);
|
||||
break;
|
||||
case DashboardMessage.getUnmappedMedia:
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { EditorHelper } from '@estruyf/vscode';
|
||||
import { window, Range, Position } from 'vscode';
|
||||
import { Dashboard } from '../../commands/Dashboard';
|
||||
import { SETTING_CONTENT_SNIPPETS, SETTING_DATE_FORMAT, TelemetryEvent } from '../../constants';
|
||||
import { SETTING_CONTENT_SNIPPETS, SETTING_DATE_FORMAT } from '../../constants';
|
||||
import { DashboardMessage } from '../../dashboardWebView/DashboardMessage';
|
||||
import {
|
||||
ArticleHelper,
|
||||
Notifications,
|
||||
Settings,
|
||||
Telemetry,
|
||||
processArticlePlaceholdersFromPath,
|
||||
processTimePlaceholders
|
||||
} from '../../helpers';
|
||||
@@ -29,7 +27,6 @@ export class SnippetListener extends BaseListener {
|
||||
this.updateSnippet(msg.payload);
|
||||
break;
|
||||
case DashboardMessage.insertSnippet:
|
||||
Telemetry.send(TelemetryEvent.insertContentSnippet);
|
||||
this.insertSnippet(msg.payload);
|
||||
break;
|
||||
case DashboardMessage.updateSnippetPlaceholders:
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import { DashboardMessage } from '../../dashboardWebView/DashboardMessage';
|
||||
import { Telemetry } from '../../helpers/Telemetry';
|
||||
import { PostMessageData } from '../../models';
|
||||
import { BaseListener } from './BaseListener';
|
||||
|
||||
export class TelemetryListener extends BaseListener {
|
||||
/**
|
||||
* Process the messages for the dashboard views
|
||||
* @param msg
|
||||
*/
|
||||
public static process(msg: PostMessageData) {
|
||||
super.process(msg);
|
||||
|
||||
switch (msg.command) {
|
||||
case DashboardMessage.sendTelemetry:
|
||||
Telemetry.send(msg.payload.event, msg.payload.properties);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ export * from './MediaListener';
|
||||
export * from './PagesListener';
|
||||
export * from './SettingsListener';
|
||||
export * from './SnippetListener';
|
||||
export * from './TelemetryListener';
|
||||
export * from './TaxonomyListener';
|
||||
export * from './LocalizationListener';
|
||||
export * from './SsgListener';
|
||||
|
||||
@@ -10,8 +10,7 @@ import {
|
||||
SETTING_GIT_SUBMODULE_BRANCH,
|
||||
SETTING_GIT_SUBMODULE_FOLDER,
|
||||
SETTING_GIT_SUBMODULE_PULL,
|
||||
SETTING_GIT_SUBMODULE_PUSH,
|
||||
TelemetryEvent
|
||||
SETTING_GIT_SUBMODULE_PUSH
|
||||
} from './../../constants';
|
||||
import { Settings } from './../../helpers/SettingsHelper';
|
||||
import { Dashboard } from '../../commands/Dashboard';
|
||||
@@ -22,8 +21,7 @@ import {
|
||||
Logger,
|
||||
Notifications,
|
||||
parseWinPath,
|
||||
processTimePlaceholders,
|
||||
Telemetry
|
||||
processTimePlaceholders
|
||||
} from '../../helpers';
|
||||
import { GeneralCommands } from './../../constants/GeneralCommands';
|
||||
import simpleGit, { SimpleGit } from 'simple-git';
|
||||
@@ -158,8 +156,6 @@ export class GitListener {
|
||||
try {
|
||||
this.sendMsg(GeneralCommands.toWebview.git.syncingStart, isSync ? 'syncing' : 'fetching');
|
||||
|
||||
Telemetry.send(isSync ? TelemetryEvent.gitSync : TelemetryEvent.gitFetch);
|
||||
|
||||
await this.pull();
|
||||
|
||||
if (isSync) {
|
||||
|
||||
@@ -5,12 +5,7 @@ import { Folders } from '../../commands/Folders';
|
||||
import { Command } from '../../panelWebView/Command';
|
||||
import { CommandToCode } from '../../panelWebView/CommandToCode';
|
||||
import { BaseListener } from './BaseListener';
|
||||
import {
|
||||
Uri,
|
||||
authentication,
|
||||
commands,
|
||||
window
|
||||
} from 'vscode';
|
||||
import { Uri, authentication, commands, window } from 'vscode';
|
||||
import {
|
||||
ArticleHelper,
|
||||
Extension,
|
||||
@@ -30,7 +25,6 @@ import {
|
||||
SETTING_DATE_FORMAT,
|
||||
SETTING_GLOBAL_ACTIVE_MODE,
|
||||
SETTING_GLOBAL_MODES,
|
||||
SETTING_SEO_TITLE_FIELD,
|
||||
SETTING_TAXONOMY_CONTENT_TYPES
|
||||
} from '../../constants';
|
||||
import { Article, Preview } from '../../commands';
|
||||
@@ -42,7 +36,7 @@ import {
|
||||
ContentType as IContentType,
|
||||
FolderInfo
|
||||
} from '../../models';
|
||||
import { encodeEmoji, fieldWhenClause } from '../../utils';
|
||||
import { encodeEmoji, fieldWhenClause, getTitleField } from '../../utils';
|
||||
import { PanelProvider } from '../../panelWebView/PanelProvider';
|
||||
import { MessageHandlerData } from '@estruyf/vscode';
|
||||
import { SponsorAi } from '../../services/SponsorAI';
|
||||
@@ -140,7 +134,7 @@ export class DataListener extends BaseListener {
|
||||
const extPath = Extension.getInstance().extensionPath;
|
||||
const panel = PanelProvider.getInstance(extPath);
|
||||
|
||||
const titleField = (Settings.get(SETTING_SEO_TITLE_FIELD) as string) || DefaultFields.Title;
|
||||
const titleField = getTitleField();
|
||||
const description = await Copilot.suggestDescription(
|
||||
articleDetails.data[titleField],
|
||||
articleDetails.content
|
||||
@@ -199,7 +193,7 @@ export class DataListener extends BaseListener {
|
||||
return;
|
||||
}
|
||||
|
||||
const titleField = (Settings.get(SETTING_SEO_TITLE_FIELD) as string) || DefaultFields.Title;
|
||||
const titleField = getTitleField();
|
||||
|
||||
const suggestion = await SponsorAi.getDescription(
|
||||
githubAuth.accessToken,
|
||||
@@ -417,7 +411,7 @@ export class DataListener extends BaseListener {
|
||||
}
|
||||
|
||||
let beforeValue: any;
|
||||
const titleField = (Settings.get(SETTING_SEO_TITLE_FIELD) as string) || DefaultFields.Title;
|
||||
const titleField = getTitleField();
|
||||
|
||||
const editor = window.activeTextEditor;
|
||||
|
||||
@@ -774,9 +768,11 @@ export class DataListener extends BaseListener {
|
||||
data && contentType ? processArticlePlaceholdersFromData(value, data, contentType) : value;
|
||||
value = processTimePlaceholders(value, dateFormat);
|
||||
value = processFmPlaceholders(value, data);
|
||||
|
||||
const titleField = getTitleField();
|
||||
value = await ArticleHelper.processCustomPlaceholders(
|
||||
value,
|
||||
data.title || '',
|
||||
data[titleField] || '',
|
||||
crntFile?.uri.fsPath || ''
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Folders } from '../../commands';
|
||||
import { SETTING_CUSTOM_SCRIPTS } from '../../constants';
|
||||
import { CustomScript, Settings } from '../../helpers';
|
||||
import { CustomScript, Notifications, Settings } from '../../helpers';
|
||||
import { CustomScript as ICustomScript, PostMessageData } from '../../models';
|
||||
import { CommandToCode } from '../../panelWebView/CommandToCode';
|
||||
import { BaseListener } from './BaseListener';
|
||||
@@ -16,6 +17,32 @@ export class ScriptListener extends BaseListener {
|
||||
case CommandToCode.runCustomScript:
|
||||
this.runCustomScript(msg);
|
||||
break;
|
||||
case CommandToCode.runFieldAction:
|
||||
this.runFieldAction(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static async runFieldAction({ command, payload, requestId }: PostMessageData) {
|
||||
if (!payload || !requestId || !command) {
|
||||
return;
|
||||
}
|
||||
|
||||
const script = payload as ICustomScript;
|
||||
if (script.script) {
|
||||
const wsFolder = Folders.getWorkspaceFolder();
|
||||
if (!wsFolder) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fieldValue = await CustomScript.singleRun(wsFolder.fsPath, script);
|
||||
|
||||
if (fieldValue) {
|
||||
this.sendRequest(command, requestId, fieldValue);
|
||||
} else {
|
||||
Notifications.error('The script did not return a field value');
|
||||
this.sendRequestError(command, requestId, 'The script did not return a field value');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,17 +5,13 @@ import { authentication, window } from 'vscode';
|
||||
import { ArticleHelper, Extension, Settings, TaxonomyHelper } from '../../helpers';
|
||||
import { BlockFieldData, CustomTaxonomyData, PostMessageData, TaxonomyType } from '../../models';
|
||||
import { DataListener } from '.';
|
||||
import {
|
||||
DefaultFields,
|
||||
SETTING_SEO_DESCRIPTION_FIELD,
|
||||
SETTING_SEO_TITLE_FIELD
|
||||
} from '../../constants';
|
||||
import { SponsorAi } from '../../services/SponsorAI';
|
||||
import { PanelProvider } from '../../panelWebView/PanelProvider';
|
||||
import { MessageHandlerData } from '@estruyf/vscode';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../localization';
|
||||
import { Copilot } from '../../services/Copilot';
|
||||
import { getDescriptionField, getTitleField } from '../../utils';
|
||||
|
||||
export class TaxonomyListener extends BaseListener {
|
||||
/**
|
||||
@@ -73,10 +69,9 @@ export class TaxonomyListener extends BaseListener {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Suggests a taxonomy for a given command, request ID, and tag type.
|
||||
*
|
||||
*
|
||||
* @param command - The command to execute.
|
||||
* @param requestId - The ID of the request.
|
||||
* @param type - The type of the tag.
|
||||
@@ -100,8 +95,8 @@ export class TaxonomyListener extends BaseListener {
|
||||
const extPath = Extension.getInstance().extensionPath;
|
||||
const panel = PanelProvider.getInstance(extPath);
|
||||
|
||||
const titleField = (Settings.get(SETTING_SEO_TITLE_FIELD) as string) || DefaultFields.Title;
|
||||
const descriptionField = (Settings.get(SETTING_SEO_DESCRIPTION_FIELD) as string) || DefaultFields.Description;
|
||||
const titleField = getTitleField();
|
||||
const descriptionField = getDescriptionField();
|
||||
|
||||
const tags = await Copilot.suggestTaxonomy(
|
||||
articleDetails.data[titleField],
|
||||
@@ -127,7 +122,7 @@ export class TaxonomyListener extends BaseListener {
|
||||
|
||||
/**
|
||||
* Suggests taxonomy based on the provided command, request ID, and tag type.
|
||||
*
|
||||
*
|
||||
* @param command - The command to execute.
|
||||
* @param requestId - The ID of the request.
|
||||
* @param type - The type of tag.
|
||||
@@ -166,9 +161,8 @@ export class TaxonomyListener extends BaseListener {
|
||||
return;
|
||||
}
|
||||
|
||||
const titleField = (Settings.get(SETTING_SEO_TITLE_FIELD) as string) || DefaultFields.Title;
|
||||
const descriptionField =
|
||||
(Settings.get(SETTING_SEO_DESCRIPTION_FIELD) as string) || DefaultFields.Description;
|
||||
const titleField = getTitleField();
|
||||
const descriptionField = getDescriptionField();
|
||||
|
||||
const suggestions = await SponsorAi.getTaxonomySuggestions(
|
||||
githubAuth.accessToken,
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export * from './localization.enum';
|
||||
export * from './localize';
|
||||
|
||||
@@ -515,6 +515,10 @@ export enum LocalizationKey {
|
||||
* {0} selected
|
||||
*/
|
||||
dashboardHeaderActionsBarItemsSelected = 'dashboard.header.actionsBar.itemsSelected',
|
||||
/**
|
||||
* Select all
|
||||
*/
|
||||
dashboardHeaderActionsBarSelectAll = 'dashboard.header.actionsBar.selectAll',
|
||||
/**
|
||||
* Delete selected files
|
||||
*/
|
||||
@@ -1416,6 +1420,14 @@ export enum LocalizationKey {
|
||||
* Unkown field type: {0}
|
||||
*/
|
||||
panelFieldsWrapperFieldUnknown = 'panel.fields.wrapperField.unknown',
|
||||
/**
|
||||
* Custom action
|
||||
*/
|
||||
panelFieldsFieldCustomActionButtonTitle = 'panel.fields.fieldCustomAction.button.title',
|
||||
/**
|
||||
* Executing field action...
|
||||
*/
|
||||
panelFieldsFieldCustomActionExecuting = 'panel.fields.fieldCustomAction.executing',
|
||||
/**
|
||||
* Actions
|
||||
*/
|
||||
@@ -2321,7 +2333,7 @@ export enum LocalizationKey {
|
||||
*/
|
||||
helpersQuestionsContentTitleAiInputQuickPickAiSeparator = 'helpers.questions.contentTitle.aiInput.quickPick.ai.separator',
|
||||
/**
|
||||
* GitHub Copilot generated title
|
||||
* GitHub Copilot suggestions
|
||||
*/
|
||||
helpersQuestionsContentTitleAiInputQuickPickCopilotSeparator = 'helpers.questions.contentTitle.aiInput.quickPick.copilot.separator',
|
||||
/**
|
||||
|
||||
5
src/localization/localize.ts
Normal file
5
src/localization/localize.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import * as l10n from '@vscode/l10n';
|
||||
|
||||
export const localize = (key: string, ...args: any[]): string => {
|
||||
return l10n.t(key, ...args);
|
||||
};
|
||||
@@ -141,6 +141,9 @@ export interface Field {
|
||||
|
||||
// When clause
|
||||
when?: WhenClause;
|
||||
|
||||
// Custom action
|
||||
actions?: CustomScript[];
|
||||
}
|
||||
|
||||
export interface NumberOptions {
|
||||
|
||||
@@ -46,5 +46,6 @@ export enum CommandToCode {
|
||||
copilotSuggestTaxonomy = 'copilot-suggest-taxonomy',
|
||||
searchByType = 'search-by-type',
|
||||
processMediaData = 'process-media-data',
|
||||
isServerStarted = 'is-server-started'
|
||||
isServerStarted = 'is-server-started',
|
||||
runFieldAction = 'run-field-action'
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
FieldsListener,
|
||||
LocalizationListener
|
||||
} from './../listeners/panel';
|
||||
import { SETTING_EXPERIMENTAL, SETTING_EXTENSIBILITY_SCRIPTS, TelemetryEvent } from '../constants';
|
||||
import { SETTING_EXPERIMENTAL } from '../constants';
|
||||
import {
|
||||
CancellationToken,
|
||||
Disposable,
|
||||
@@ -27,9 +27,8 @@ import { WebviewHelper } from '@estruyf/vscode';
|
||||
import { Extension } from '../helpers/Extension';
|
||||
import { Telemetry } from '../helpers/Telemetry';
|
||||
import { GitListener, ModeListener } from '../listeners/general';
|
||||
import { Folders } from '../commands';
|
||||
import { basename } from 'path';
|
||||
import { ignoreMsgCommand } from '../utils';
|
||||
import { getExtensibilityScripts, ignoreMsgCommand } from '../utils';
|
||||
|
||||
export class PanelProvider implements WebviewViewProvider, Disposable {
|
||||
public static readonly viewType = 'frontMatter.explorer';
|
||||
@@ -120,7 +119,6 @@ export class PanelProvider implements WebviewViewProvider, Disposable {
|
||||
|
||||
webviewView.onDidChangeVisibility(() => {
|
||||
if (this.visible) {
|
||||
Telemetry.send(TelemetryEvent.openPanelWebview);
|
||||
DataListener.getFileData();
|
||||
}
|
||||
});
|
||||
@@ -242,20 +240,8 @@ export class PanelProvider implements WebviewViewProvider, Disposable {
|
||||
|
||||
// Get experimental setting
|
||||
const experimental = Settings.get(SETTING_EXPERIMENTAL);
|
||||
const extensibilityScripts = Settings.get<string[]>(SETTING_EXTENSIBILITY_SCRIPTS) || [];
|
||||
|
||||
const scriptsToLoad: string[] = [];
|
||||
if (experimental) {
|
||||
for (const script of extensibilityScripts) {
|
||||
if (script.startsWith('https://')) {
|
||||
scriptsToLoad.push(script);
|
||||
} else {
|
||||
const absScriptPath = Folders.getAbsFilePath(script);
|
||||
const scriptUri = webView.asWebviewUri(Uri.file(absScriptPath));
|
||||
scriptsToLoad.push(scriptUri.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
const scriptsToLoad: string[] = getExtensibilityScripts(webView);
|
||||
|
||||
const csp = [
|
||||
`default-src 'none';`,
|
||||
@@ -289,9 +275,9 @@ export class PanelProvider implements WebviewViewProvider, Disposable {
|
||||
<body>
|
||||
<div id="app" data-isProd="${isProd}" data-environment="${
|
||||
isBeta ? 'BETA' : 'main'
|
||||
}" data-version="${
|
||||
version.usedVersion
|
||||
}" data-is-crash-disabled="${!Telemetry.isVscodeEnabled()}"></div>
|
||||
}" data-version="${version.usedVersion}" ${
|
||||
experimental ? `data-experimental="${experimental}"` : ''
|
||||
} data-is-crash-disabled="${!Telemetry.isVscodeEnabled()}"></div>
|
||||
|
||||
${(scriptsToLoad || [])
|
||||
.map((script) => {
|
||||
|
||||
@@ -137,7 +137,8 @@ export const ViewPanel: React.FunctionComponent<IViewPanelProps> = (
|
||||
<FeatureFlag features={mode?.features || DEFAULT_PANEL_FEATURE_FLAGS} flag={FEATURE_FLAG.panel.seo}>
|
||||
<SeoStatus
|
||||
seo={settings.seo}
|
||||
data={metadata}
|
||||
metadata={metadata}
|
||||
settings={settings}
|
||||
focusElm={focusElm}
|
||||
unsetFocus={unsetFocus}
|
||||
/>
|
||||
|
||||
@@ -8,13 +8,14 @@ import { IMetadata } from '../Metadata';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../../localization';
|
||||
import { VSCodeLabel } from '../VSCode';
|
||||
import { DefaultFields } from '../../../constants';
|
||||
|
||||
export interface IContentTypeValidatorProps {
|
||||
fields: Field[];
|
||||
metadata: IMetadata;
|
||||
}
|
||||
|
||||
const fieldsToIgnore = [`filePath`, `articleDetails`, `slug`, `keywords`, `type`];
|
||||
const fieldsToIgnore = [`filePath`, `articleDetails`, DefaultFields.Slug, DefaultFields.Keywords, DefaultFields.Type, DefaultFields.ContentType];
|
||||
|
||||
export const ContentTypeValidator: React.FunctionComponent<IContentTypeValidatorProps> = ({
|
||||
fields,
|
||||
|
||||
85
src/panelWebView/components/Fields/FieldCustomAction.tsx
Normal file
85
src/panelWebView/components/Fields/FieldCustomAction.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import * as React from 'react';
|
||||
import { CustomScript } from '../../../models';
|
||||
import { messageHandler } from '@estruyf/vscode/dist/client';
|
||||
import { CodeBracketIcon, CommandLineIcon } from '@heroicons/react/24/solid';
|
||||
import { CommandToCode } from '../../CommandToCode';
|
||||
import { LocalizationKey, localize } from '../../../localization';
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '../../../components/shadcn/Dropdown';
|
||||
|
||||
export interface IFieldCustomActionProps {
|
||||
actions: CustomScript[];
|
||||
disabled?: boolean;
|
||||
triggerLoading?: (message?: string) => void;
|
||||
onChange: (value: any) => void;
|
||||
}
|
||||
|
||||
export const FieldCustomAction: React.FunctionComponent<IFieldCustomActionProps> = ({ actions, disabled, triggerLoading, onChange }: React.PropsWithChildren<IFieldCustomActionProps>) => {
|
||||
|
||||
const triggerAction = React.useCallback((action: CustomScript) => {
|
||||
if (triggerLoading) {
|
||||
triggerLoading(localize(LocalizationKey.panelFieldsFieldCustomActionExecuting));
|
||||
}
|
||||
|
||||
messageHandler.request(CommandToCode.runFieldAction, {
|
||||
...action
|
||||
}).then((value: any) => {
|
||||
onChange(value);
|
||||
|
||||
if (triggerLoading) {
|
||||
triggerLoading();
|
||||
}
|
||||
}).catch(() => {
|
||||
console.error('Error while running the custom action');
|
||||
|
||||
if (triggerLoading) {
|
||||
triggerLoading();
|
||||
}
|
||||
});
|
||||
}, [triggerLoading, onChange]);
|
||||
|
||||
if (!actions) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (actions.length === 1) {
|
||||
const action = actions[0];
|
||||
return (
|
||||
<button
|
||||
className="metadata_field__title__action inline-block text-[var(--vscode-editor-foreground)] disabled:opacity-50"
|
||||
title={action?.title || localize(LocalizationKey.panelFieldsFieldCustomActionButtonTitle)}
|
||||
type="button"
|
||||
onClick={triggerAction.bind(null, action)}
|
||||
disabled={disabled}
|
||||
>
|
||||
<span className='sr-only'>{action?.title || localize(LocalizationKey.panelFieldsFieldCustomActionButtonTitle)}</span>
|
||||
<CommandLineIcon style={{ height: "16px", width: "16px" }} aria-hidden="true" />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger
|
||||
title={localize(LocalizationKey.commonOpenCustomActions)}
|
||||
className='metadata_field__title__action inline-block text-[var(--vscode-editor-foreground)] disabled:opacity-50'>
|
||||
<span className="sr-only">{localize(LocalizationKey.commonOpenCustomActions)}</span>
|
||||
<CommandLineIcon style={{ height: "16px", width: "16px" }} aria-hidden="true" />
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
<DropdownMenuContent align='end' className='p-0'>
|
||||
{
|
||||
actions.map((action) => (
|
||||
<DropdownMenuItem
|
||||
key={action.id || action.title}
|
||||
title={action.title}
|
||||
className={`focus:bg-[var(--vscode-button-background)] focus:text-[var(--vscode-button-foreground)] focus:outline-0 rounded-none`}
|
||||
onClick={(e) => triggerAction(action)}>
|
||||
<CommandLineIcon className={`mr-2 h-4 w-4`} aria-hidden={true} />
|
||||
<span>{action.title}</span>
|
||||
</DropdownMenuItem>
|
||||
))
|
||||
}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)
|
||||
};
|
||||
@@ -1,6 +1,8 @@
|
||||
import * as React from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { RequiredAsterix } from './RequiredAsterix';
|
||||
import { CustomScript } from '../../../models';
|
||||
import { FieldCustomAction } from './FieldCustomAction';
|
||||
|
||||
export interface IFieldTitleProps {
|
||||
label: string | JSX.Element;
|
||||
@@ -8,6 +10,10 @@ export interface IFieldTitleProps {
|
||||
className?: string;
|
||||
required?: boolean;
|
||||
actionElement?: JSX.Element;
|
||||
customActions?: CustomScript[];
|
||||
isDisabled?: boolean;
|
||||
triggerLoading?: (message?: string) => void;
|
||||
onChange?: (value: any) => void;
|
||||
}
|
||||
|
||||
export const FieldTitle: React.FunctionComponent<IFieldTitleProps> = ({
|
||||
@@ -16,6 +22,10 @@ export const FieldTitle: React.FunctionComponent<IFieldTitleProps> = ({
|
||||
className,
|
||||
required,
|
||||
actionElement,
|
||||
customActions,
|
||||
isDisabled,
|
||||
triggerLoading,
|
||||
onChange,
|
||||
}: React.PropsWithChildren<IFieldTitleProps>) => {
|
||||
const Icon = useMemo(() => {
|
||||
return icon ? React.cloneElement(icon, { style: { width: '16px', height: '16px' } }) : null;
|
||||
@@ -29,7 +39,19 @@ export const FieldTitle: React.FunctionComponent<IFieldTitleProps> = ({
|
||||
<RequiredAsterix required={required} />
|
||||
</label>
|
||||
|
||||
{actionElement}
|
||||
<div className="flex gap-4">
|
||||
{actionElement}
|
||||
|
||||
{
|
||||
customActions && onChange && (
|
||||
<FieldCustomAction
|
||||
actions={customActions}
|
||||
disabled={isDisabled}
|
||||
triggerLoading={triggerLoading}
|
||||
onChange={onChange} />
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ import { PhotoIcon } from '@heroicons/react/24/outline';
|
||||
import * as React from 'react';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { DefaultFieldValues } from '../../../constants';
|
||||
import { BaseFieldProps, BlockFieldData } from '../../../models';
|
||||
import { BaseFieldProps, BlockFieldData, CustomScript } from '../../../models';
|
||||
import { CommandToCode } from '../../CommandToCode';
|
||||
import { FieldTitle } from './FieldTitle';
|
||||
import { PreviewImage } from './PreviewImage';
|
||||
@@ -23,6 +23,7 @@ export interface IPreviewImageFieldProps
|
||||
parents?: string[];
|
||||
multiple?: boolean;
|
||||
blockData?: BlockFieldData;
|
||||
actions?: CustomScript[];
|
||||
onChange: (value: string | string[] | null) => void;
|
||||
}
|
||||
|
||||
@@ -36,8 +37,10 @@ export const PreviewImageField: React.FunctionComponent<IPreviewImageFieldProps>
|
||||
filePath,
|
||||
multiple,
|
||||
parents,
|
||||
actions,
|
||||
required
|
||||
}: React.PropsWithChildren<IPreviewImageFieldProps>) => {
|
||||
const [loading, setLoading] = React.useState<string | undefined>(undefined);
|
||||
const [imageData, setImageData] = React.useState<PreviewImageValue | PreviewImageValue[] | null>(null);
|
||||
|
||||
const selectImage = useCallback(() => {
|
||||
@@ -95,7 +98,14 @@ export const PreviewImageField: React.FunctionComponent<IPreviewImageFieldProps>
|
||||
|
||||
return (
|
||||
<div className={`metadata_field`}>
|
||||
<FieldTitle label={label} icon={<PhotoIcon />} required={required} />
|
||||
<FieldTitle
|
||||
label={label}
|
||||
icon={<PhotoIcon />}
|
||||
required={required}
|
||||
isDisabled={!!loading}
|
||||
customActions={actions}
|
||||
triggerLoading={(message) => setLoading(message)}
|
||||
onChange={(value: string) => onChange(value)} />
|
||||
|
||||
<div
|
||||
className={`metadata_field__preview_image ${multiple && imageData && (imageData as PreviewImageValue[]).length > 0
|
||||
|
||||
@@ -5,7 +5,7 @@ import { CommandToCode } from '../../CommandToCode';
|
||||
import { TagType } from '../../TagType';
|
||||
import Downshift from 'downshift';
|
||||
import { AddIcon } from '../Icons/AddIcon';
|
||||
import { BlockFieldData, CustomTaxonomyData } from '../../../models';
|
||||
import { BlockFieldData, CustomScript, CustomTaxonomyData } from '../../../models';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { messageHandler, Messenger } from '@estruyf/vscode/dist/client';
|
||||
import { FieldMessage } from '../Fields/FieldMessage';
|
||||
@@ -13,8 +13,7 @@ import { FieldTitle } from '../Fields/FieldTitle';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { PanelSettingsAtom } from '../../state';
|
||||
import { SparklesIcon } from '@heroicons/react/24/outline';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../../localization';
|
||||
import { LocalizationKey, localize } from '../../../localization';
|
||||
import useDropdownStyle from '../../hooks/useDropdownStyle';
|
||||
import { CopilotIcon } from '../Icons';
|
||||
|
||||
@@ -37,6 +36,7 @@ export interface ITagPickerProps {
|
||||
limit?: number;
|
||||
required?: boolean;
|
||||
renderAsString?: boolean;
|
||||
actions?: CustomScript[];
|
||||
}
|
||||
|
||||
const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
|
||||
@@ -56,7 +56,8 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
|
||||
blockData,
|
||||
limit,
|
||||
required,
|
||||
renderAsString
|
||||
renderAsString,
|
||||
actions
|
||||
}: React.PropsWithChildren<ITagPickerProps>) => {
|
||||
const [selected, setSelected] = React.useState<string[]>([]);
|
||||
const [inputValue, setInputValue] = React.useState<string>('');
|
||||
@@ -65,7 +66,7 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
|
||||
const { getDropdownStyle } = useDropdownStyle(inputRef as any);
|
||||
const dsRef = React.useRef<Downshift<string> | null>(null);
|
||||
const settings = useRecoilValue(PanelSettingsAtom);
|
||||
const [loading, setLoading] = React.useState<boolean>(false);
|
||||
const [loading, setLoading] = React.useState<string | undefined>(undefined);
|
||||
|
||||
/**
|
||||
* Removes an option
|
||||
@@ -249,25 +250,29 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
|
||||
[options, inputRef, selected, freeform]
|
||||
);
|
||||
|
||||
const updateTaxonomy = (values: string[]) => {
|
||||
if (values && values instanceof Array && values.length > 0) {
|
||||
const uniqValues = Array.from(new Set([...selected, ...values]));
|
||||
setSelected(uniqValues);
|
||||
sendUpdate(uniqValues);
|
||||
setInputValue('');
|
||||
}
|
||||
}
|
||||
|
||||
const suggestTaxonomy = useCallback(
|
||||
(aiType: 'ai' | 'copilot', type: TagType) => {
|
||||
setLoading(true);
|
||||
setLoading(localize(LocalizationKey.panelTagPickerAiGenerating));
|
||||
|
||||
const command =
|
||||
aiType === 'ai' ? CommandToCode.aiSuggestTaxonomy : CommandToCode.copilotSuggestTaxonomy;
|
||||
messageHandler
|
||||
.request<string[]>(command, type)
|
||||
.then((values) => {
|
||||
setLoading(false);
|
||||
if (values && values instanceof Array && values.length > 0) {
|
||||
const uniqValues = Array.from(new Set([...selected, ...values]));
|
||||
setSelected(uniqValues);
|
||||
sendUpdate(uniqValues);
|
||||
setInputValue('');
|
||||
}
|
||||
setLoading(undefined);
|
||||
updateTaxonomy(values)
|
||||
})
|
||||
.catch(() => {
|
||||
setLoading(false);
|
||||
setLoading(undefined);
|
||||
});
|
||||
},
|
||||
[selected]
|
||||
@@ -286,13 +291,13 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
|
||||
|
||||
const inputPlaceholder = useMemo((): string => {
|
||||
if (checkIsDisabled()) {
|
||||
return l10n.t(
|
||||
return localize(
|
||||
LocalizationKey.panelTagPickerInputPlaceholderDisabled,
|
||||
`${limit} ${label || type.toLowerCase()}`
|
||||
);
|
||||
}
|
||||
|
||||
return l10n.t(LocalizationKey.panelTagPickerInputPlaceholderEmpty, label || type.toLowerCase());
|
||||
return localize(LocalizationKey.panelTagPickerInputPlaceholderEmpty, label || type.toLowerCase());
|
||||
}, [label, type, checkIsDisabled]);
|
||||
|
||||
const showRequiredState = useMemo(() => {
|
||||
@@ -305,17 +310,17 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex gap-4">
|
||||
<>
|
||||
{settings?.aiEnabled && (
|
||||
<button
|
||||
className="metadata_field__title__action"
|
||||
title={l10n.t(
|
||||
title={localize(
|
||||
LocalizationKey.panelTagPickerAiSuggest,
|
||||
label?.toLowerCase() || type.toLowerCase()
|
||||
)}
|
||||
type="button"
|
||||
onClick={() => suggestTaxonomy('ai', type)}
|
||||
disabled={loading}
|
||||
disabled={!!loading}
|
||||
>
|
||||
<SparklesIcon />
|
||||
</button>
|
||||
@@ -324,18 +329,18 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
|
||||
{settings?.copilotEnabled && (
|
||||
<button
|
||||
className="metadata_field__title__action"
|
||||
title={l10n.t(
|
||||
title={localize(
|
||||
LocalizationKey.panelTagPickerCopilotSuggest,
|
||||
label?.toLowerCase() || type.toLowerCase()
|
||||
)}
|
||||
type="button"
|
||||
onClick={() => suggestTaxonomy('copilot', type)}
|
||||
disabled={loading}
|
||||
disabled={!!loading}
|
||||
>
|
||||
<CopilotIcon />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}, [settings?.aiEnabled, settings?.copilotEnabled, label, type]);
|
||||
|
||||
@@ -376,7 +381,7 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
|
||||
<>
|
||||
{` `}
|
||||
<span style={{ fontWeight: 'lighter' }}>
|
||||
({l10n.t(LocalizationKey.panelTagPickerLimit, limit)})
|
||||
({localize(LocalizationKey.panelTagPickerLimit, limit)})
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
@@ -387,12 +392,16 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
|
||||
actionElement={actionElement}
|
||||
icon={icon}
|
||||
required={required}
|
||||
isDisabled={!!loading}
|
||||
customActions={actions}
|
||||
triggerLoading={(message) => setLoading(message)}
|
||||
onChange={updateTaxonomy}
|
||||
/>
|
||||
|
||||
<div className="relative">
|
||||
{loading && (
|
||||
<div className="metadata_field__loading">
|
||||
{l10n.t(LocalizationKey.panelTagPickerAiGenerating)}
|
||||
{loading}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -418,9 +427,8 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
|
||||
<>
|
||||
<div
|
||||
{...getRootProps(undefined, { suppressRefError: true })}
|
||||
className={`article__tags__input ${freeform ? 'freeform' : ''} ${
|
||||
showRequiredState ? 'required' : ''
|
||||
}`}
|
||||
className={`article__tags__input ${freeform ? 'freeform' : ''} ${showRequiredState ? 'required' : ''
|
||||
}`}
|
||||
>
|
||||
<input
|
||||
{...getInputProps({
|
||||
@@ -443,7 +451,7 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
|
||||
{freeform && (
|
||||
<button
|
||||
className={`article__tags__input__button`}
|
||||
title={l10n.t(LocalizationKey.panelTagPickerUnkown)}
|
||||
title={localize(LocalizationKey.panelTagPickerUnkown)}
|
||||
disabled={!inputValue || checkIsDisabled()}
|
||||
onClick={() => insertUnkownTag(closeMenu)}
|
||||
>
|
||||
|
||||
@@ -2,14 +2,13 @@ import { PencilIcon, SparklesIcon } from '@heroicons/react/24/outline';
|
||||
import * as React from 'react';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { BaseFieldProps, PanelSettings } from '../../../models';
|
||||
import { BaseFieldProps, CustomScript, PanelSettings } from '../../../models';
|
||||
import { RequiredFieldsAtom } from '../../state';
|
||||
import { FieldTitle } from './FieldTitle';
|
||||
import { FieldMessage } from './FieldMessage';
|
||||
import { messageHandler } from '@estruyf/vscode/dist/client';
|
||||
import { CommandToCode } from '../../CommandToCode';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../../localization';
|
||||
import { LocalizationKey, localize } from '../../../localization';
|
||||
import { useDebounce } from '../../../hooks/useDebounce';
|
||||
import { CopilotIcon } from '../Icons';
|
||||
|
||||
@@ -23,6 +22,7 @@ export interface ITextFieldProps extends BaseFieldProps<string> {
|
||||
name: string;
|
||||
placeholder?: string;
|
||||
settings: PanelSettings;
|
||||
actions?: CustomScript[];
|
||||
onChange: (txtValue: string) => void;
|
||||
}
|
||||
|
||||
@@ -40,11 +40,12 @@ export const TextField: React.FunctionComponent<ITextFieldProps> = ({
|
||||
name,
|
||||
settings,
|
||||
onChange,
|
||||
actions,
|
||||
required
|
||||
}: React.PropsWithChildren<ITextFieldProps>) => {
|
||||
const [, setRequiredFields] = useRecoilState(RequiredFieldsAtom);
|
||||
const [text, setText] = React.useState<string | null | undefined>(undefined);
|
||||
const [loading, setLoading] = React.useState<boolean>(false);
|
||||
const [loading, setLoading] = React.useState<string | undefined>(undefined);
|
||||
const [lastUpdated, setLastUpdated] = React.useState<number | null>(null);
|
||||
const debouncedText = useDebounce<string | null | undefined>(text, DEBOUNCE_TIME);
|
||||
|
||||
@@ -93,13 +94,14 @@ export const TextField: React.FunctionComponent<ITextFieldProps> = ({
|
||||
}, [showRequiredState, isValid]);
|
||||
|
||||
const suggestDescription = (type: 'ai' | 'copilot') => {
|
||||
setLoading(true);
|
||||
setLoading(localize(LocalizationKey.panelFieldsTextFieldAiGenerate));
|
||||
|
||||
messageHandler
|
||||
.request<string>(
|
||||
type === 'copilot' ? CommandToCode.copilotSuggestDescription : CommandToCode.aiSuggestDescription
|
||||
)
|
||||
.then((suggestion) => {
|
||||
setLoading(false);
|
||||
setLoading(undefined);
|
||||
|
||||
if (suggestion) {
|
||||
setText(suggestion);
|
||||
@@ -107,7 +109,7 @@ export const TextField: React.FunctionComponent<ITextFieldProps> = ({
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
setLoading(false);
|
||||
setLoading(undefined);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -117,14 +119,14 @@ export const TextField: React.FunctionComponent<ITextFieldProps> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex gap-4">
|
||||
<>
|
||||
{settings?.aiEnabled && (
|
||||
<button
|
||||
className="metadata_field__title__action inline-block text-[var(--vscode-editor-foreground)] disabled:opacity-50"
|
||||
title={l10n.t(LocalizationKey.panelFieldsTextFieldAiMessage, label?.toLowerCase())}
|
||||
title={localize(LocalizationKey.panelFieldsTextFieldAiMessage, label?.toLowerCase())}
|
||||
type="button"
|
||||
onClick={() => suggestDescription('ai')}
|
||||
disabled={loading}
|
||||
disabled={!!loading}
|
||||
>
|
||||
<SparklesIcon />
|
||||
</button>
|
||||
@@ -133,17 +135,17 @@ export const TextField: React.FunctionComponent<ITextFieldProps> = ({
|
||||
{settings?.copilotEnabled && (
|
||||
<button
|
||||
className="metadata_field__title__action inline-block text-[var(--vscode-editor-foreground)] disabled:opacity-50"
|
||||
title={l10n.t(LocalizationKey.panelFieldsTextFieldCopilotMessage, label?.toLowerCase())}
|
||||
title={localize(LocalizationKey.panelFieldsTextFieldCopilotMessage, label?.toLowerCase())}
|
||||
type="button"
|
||||
onClick={() => suggestDescription('copilot')}
|
||||
disabled={loading}
|
||||
disabled={!!loading}
|
||||
>
|
||||
<CopilotIcon />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}, [settings?.aiEnabled, name]);
|
||||
}, [settings?.aiEnabled, settings?.copilotEnabled, name, actions, loading]);
|
||||
|
||||
useEffect(() => {
|
||||
if (text !== value && (lastUpdated === null || Date.now() - DEBOUNCE_TIME > lastUpdated)) {
|
||||
@@ -165,18 +167,22 @@ export const TextField: React.FunctionComponent<ITextFieldProps> = ({
|
||||
actionElement={actionElement}
|
||||
icon={<PencilIcon />}
|
||||
required={required}
|
||||
isDisabled={!!loading}
|
||||
customActions={actions}
|
||||
triggerLoading={(message) => setLoading(message)}
|
||||
onChange={onTextChange}
|
||||
/>
|
||||
|
||||
<div className='relative'>
|
||||
{loading && (
|
||||
<div className="metadata_field__loading">
|
||||
{l10n.t(LocalizationKey.panelFieldsTextFieldAiGenerate)}
|
||||
{loading}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{wysiwyg ? (
|
||||
<React.Suspense
|
||||
fallback={<div>{l10n.t(LocalizationKey.panelFieldsTextFieldLoading)}</div>}
|
||||
fallback={<div>{localize(LocalizationKey.panelFieldsTextFieldLoading)}</div>}
|
||||
>
|
||||
<WysiwygField text={text || ''} onChange={onTextChange} />
|
||||
</React.Suspense>
|
||||
@@ -206,7 +212,7 @@ export const TextField: React.FunctionComponent<ITextFieldProps> = ({
|
||||
|
||||
{limit && limit > 0 && (text || '').length > limit && (
|
||||
<div className={`metadata_field__limit`}>
|
||||
{l10n.t(LocalizationKey.panelFieldsTextFieldLimit, `${(text || '').length}/${limit}`)}
|
||||
{localize(LocalizationKey.panelFieldsTextFieldLimit, `${(text || '').length}/${limit}`)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -216,6 +216,7 @@ export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
|
||||
value={(fieldValue as string) || null}
|
||||
required={!!field.required}
|
||||
settings={settings}
|
||||
actions={field.actions}
|
||||
/>
|
||||
</FieldBoundary>
|
||||
);
|
||||
@@ -251,6 +252,7 @@ export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
|
||||
multiple={field.multiple}
|
||||
blockData={blockData}
|
||||
onChange={onFieldChange}
|
||||
actions={field.actions}
|
||||
/>
|
||||
</FieldBoundary>
|
||||
);
|
||||
@@ -307,6 +309,7 @@ export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
|
||||
limit={field.taxonomyLimit}
|
||||
renderAsString={field.singleValueAsString}
|
||||
required={!!field.required}
|
||||
actions={field.actions}
|
||||
/>
|
||||
</FieldBoundary>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { SEO } from '../../models/PanelSettings';
|
||||
import { PanelSettings, SEO } from '../../models/PanelSettings';
|
||||
import { TagType } from '../TagType';
|
||||
import { ArticleDetails } from './ArticleDetails';
|
||||
import { Collapsible } from './Collapsible';
|
||||
@@ -8,49 +8,55 @@ import { SymbolKeywordIcon } from './Icons/SymbolKeywordIcon';
|
||||
import { SeoFieldInfo } from './SeoFieldInfo';
|
||||
import { SeoKeywords } from './SeoKeywords';
|
||||
import { TagPicker } from './Fields/TagPicker';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../../localization';
|
||||
import { LocalizationKey, localize } from '../../localization';
|
||||
import { VSCodeTable, VSCodeTableBody, VSCodeTableHead, VSCodeTableHeader, VSCodeTableRow } from './VSCode/VSCodeTable';
|
||||
import useContentType from '../../hooks/useContentType';
|
||||
|
||||
export interface ISeoStatusProps {
|
||||
seo: SEO;
|
||||
data: any;
|
||||
metadata: any;
|
||||
settings: PanelSettings | undefined;
|
||||
focusElm: TagType | null;
|
||||
unsetFocus: () => void;
|
||||
}
|
||||
|
||||
const SeoStatus: React.FunctionComponent<ISeoStatusProps> = ({
|
||||
data,
|
||||
metadata,
|
||||
seo,
|
||||
settings,
|
||||
focusElm,
|
||||
unsetFocus
|
||||
}: React.PropsWithChildren<ISeoStatusProps>) => {
|
||||
const { title, slug } = data;
|
||||
const contentType = useContentType(settings, metadata);
|
||||
const { slug } = metadata;
|
||||
|
||||
const { descriptionField, titleField } = seo;
|
||||
|
||||
const tableContent = React.useMemo(() => {
|
||||
const titleFieldName = contentType?.fields.find(f => f.name === titleField)?.title || titleField;
|
||||
const descriptionFieldName = contentType?.fields.find(f => f.name === descriptionField)?.title || descriptionField;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={`seo__status__details`}>
|
||||
<h4>{l10n.t(LocalizationKey.panelSeoStatusTitle)}</h4>
|
||||
<h4>{localize(LocalizationKey.panelSeoStatusTitle)}</h4>
|
||||
|
||||
<VSCodeTable>
|
||||
<VSCodeTableHeader>
|
||||
<VSCodeTableRow>
|
||||
<VSCodeTableHead>{l10n.t(LocalizationKey.panelSeoStatusHeaderProperty)}</VSCodeTableHead>
|
||||
<VSCodeTableHead>{l10n.t(LocalizationKey.panelSeoStatusHeaderLength)}</VSCodeTableHead>
|
||||
<VSCodeTableHead>{l10n.t(LocalizationKey.panelSeoStatusHeaderValid)}</VSCodeTableHead>
|
||||
<VSCodeTableHead>{localize(LocalizationKey.panelSeoStatusHeaderProperty)}</VSCodeTableHead>
|
||||
<VSCodeTableHead>{localize(LocalizationKey.panelSeoStatusHeaderLength)}</VSCodeTableHead>
|
||||
<VSCodeTableHead>{localize(LocalizationKey.panelSeoStatusHeaderValid)}</VSCodeTableHead>
|
||||
</VSCodeTableRow>
|
||||
</VSCodeTableHeader>
|
||||
|
||||
<VSCodeTableBody>
|
||||
{data[titleField] && seo.title > 0 ? (
|
||||
{metadata[titleField] && seo.title > 0 ? (
|
||||
<SeoFieldInfo
|
||||
title={titleField}
|
||||
value={data[titleField].length}
|
||||
recommendation={l10n.t(LocalizationKey.panelSeoStatusSeoFieldInfoCharacters, seo.title)}
|
||||
isValid={data[titleField].length <= seo.title}
|
||||
title={titleFieldName}
|
||||
value={metadata[titleField].length}
|
||||
recommendation={localize(LocalizationKey.panelSeoStatusSeoFieldInfoCharacters, seo.title)}
|
||||
isValid={metadata[titleField].length <= seo.title}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
@@ -58,25 +64,25 @@ const SeoStatus: React.FunctionComponent<ISeoStatusProps> = ({
|
||||
<SeoFieldInfo
|
||||
title={`slug`}
|
||||
value={slug.length}
|
||||
recommendation={l10n.t(LocalizationKey.panelSeoStatusSeoFieldInfoCharacters, seo.slug)}
|
||||
recommendation={localize(LocalizationKey.panelSeoStatusSeoFieldInfoCharacters, seo.slug)}
|
||||
isValid={slug.length <= seo.slug}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{data[descriptionField] && seo.description > 0 ? (
|
||||
{metadata[descriptionField] && seo.description > 0 ? (
|
||||
<SeoFieldInfo
|
||||
title={descriptionField}
|
||||
value={data[descriptionField].length}
|
||||
recommendation={l10n.t(LocalizationKey.panelSeoStatusSeoFieldInfoCharacters, seo.description)}
|
||||
isValid={data[descriptionField].length <= seo.description}
|
||||
title={descriptionFieldName}
|
||||
value={metadata[descriptionField].length}
|
||||
recommendation={localize(LocalizationKey.panelSeoStatusSeoFieldInfoCharacters, seo.description)}
|
||||
isValid={metadata[descriptionField].length <= seo.description}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{seo.content > 0 && data?.articleDetails?.wordCount > 0 ? (
|
||||
{seo.content > 0 && metadata?.articleDetails?.wordCount > 0 ? (
|
||||
<SeoFieldInfo
|
||||
title={l10n.t(LocalizationKey.panelSeoStatusSeoFieldInfoArticle)}
|
||||
value={data?.articleDetails?.wordCount}
|
||||
recommendation={l10n.t(LocalizationKey.panelSeoStatusSeoFieldInfoWords, seo.content)}
|
||||
title={localize(LocalizationKey.panelSeoStatusSeoFieldInfoArticle)}
|
||||
value={metadata?.articleDetails?.wordCount}
|
||||
recommendation={localize(LocalizationKey.panelSeoStatusSeoFieldInfoWords, seo.content)}
|
||||
/>
|
||||
) : null}
|
||||
</VSCodeTableBody>
|
||||
@@ -84,20 +90,20 @@ const SeoStatus: React.FunctionComponent<ISeoStatusProps> = ({
|
||||
</div>
|
||||
|
||||
<SeoKeywords
|
||||
keywords={data?.keywords}
|
||||
title={title}
|
||||
description={data[descriptionField]}
|
||||
slug={data.slug}
|
||||
headings={data?.articleDetails?.headingsText}
|
||||
wordCount={data?.articleDetails?.wordCount}
|
||||
content={data?.articleDetails?.content}
|
||||
keywords={metadata?.keywords}
|
||||
title={metadata[titleField]}
|
||||
description={metadata[descriptionField]}
|
||||
slug={metadata.slug}
|
||||
headings={metadata?.articleDetails?.headingsText}
|
||||
wordCount={metadata?.articleDetails?.wordCount}
|
||||
content={metadata?.articleDetails?.content}
|
||||
/>
|
||||
|
||||
<FieldBoundary fieldName={`Keywords`}>
|
||||
<TagPicker
|
||||
type={TagType.keywords}
|
||||
icon={<SymbolKeywordIcon />}
|
||||
crntSelected={(data.keywords as string[]) || []}
|
||||
crntSelected={(metadata.keywords as string[]) || []}
|
||||
options={[]}
|
||||
freeform={true}
|
||||
focussed={focusElm === TagType.keywords}
|
||||
@@ -106,17 +112,17 @@ const SeoStatus: React.FunctionComponent<ISeoStatusProps> = ({
|
||||
/>
|
||||
</FieldBoundary>
|
||||
|
||||
<ArticleDetails details={data.articleDetails} />
|
||||
<ArticleDetails details={metadata.articleDetails} />
|
||||
</div>
|
||||
);
|
||||
}, [data, seo, focusElm, unsetFocus]);
|
||||
}, [contentType, metadata, seo, focusElm, unsetFocus]);
|
||||
|
||||
return (
|
||||
<Collapsible id={`seo`} title={l10n.t(LocalizationKey.panelSeoStatusCollapsibleTitle)}>
|
||||
{!title && !data[descriptionField] ? (
|
||||
<Collapsible id={`seo`} title={localize(LocalizationKey.panelSeoStatusCollapsibleTitle)}>
|
||||
{!metadata[titleField] && !metadata[descriptionField] ? (
|
||||
<div className={`seo__status__empty`}>
|
||||
<p>
|
||||
{l10n.t(LocalizationKey.panelSeoStatusRequired, "Title", descriptionField)}
|
||||
{localize(LocalizationKey.panelSeoStatusRequired, titleField, descriptionField)}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
|
||||
@@ -345,6 +345,7 @@ button {
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
color: var(--vscode-disabledForeground);
|
||||
background: none;
|
||||
}
|
||||
|
||||
svg {
|
||||
|
||||
35
src/providers/UriHandler.ts
Normal file
35
src/providers/UriHandler.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { commands, Uri, window } from 'vscode';
|
||||
import { EXTENSION_COMMAND_PREFIX } from '../constants';
|
||||
|
||||
export class UriHandler {
|
||||
/**
|
||||
* Register the URI handler
|
||||
*/
|
||||
public static register() {
|
||||
window.registerUriHandler({
|
||||
handleUri(uri: Uri) {
|
||||
const queryParams = new URLSearchParams(uri.query);
|
||||
if (!queryParams.has('command')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const command = queryParams.get('command');
|
||||
let args = queryParams.get('args');
|
||||
|
||||
if (!command || !command.startsWith(EXTENSION_COMMAND_PREFIX)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (args) {
|
||||
try {
|
||||
args = JSON.parse(args);
|
||||
} catch (error) {
|
||||
// Ignore error
|
||||
}
|
||||
}
|
||||
|
||||
commands.executeCommand(command, args);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,11 @@ import {
|
||||
version as VscodeVersion
|
||||
} from 'vscode';
|
||||
import { Logger, Settings, TaxonomyHelper } from '../helpers';
|
||||
import { SETTING_SEO_DESCRIPTION_LENGTH, SETTING_SEO_TITLE_LENGTH } from '../constants';
|
||||
import {
|
||||
SETTING_COPILOT_FAMILY,
|
||||
SETTING_SEO_DESCRIPTION_LENGTH,
|
||||
SETTING_SEO_TITLE_LENGTH
|
||||
} from '../constants';
|
||||
import { TagType } from '../panelWebView/TagType';
|
||||
import { TaxonomyType } from '../models';
|
||||
|
||||
@@ -20,8 +24,9 @@ export class Copilot {
|
||||
* @returns A promise that resolves to a boolean indicating whether the extension is installed.
|
||||
*/
|
||||
public static async isInstalled(): Promise<boolean> {
|
||||
if (!VscodeVersion.includes('insider')) {
|
||||
// At the moment Copilot is only available in the insider version of VS Code
|
||||
const version = VscodeVersion.split('.').map((v) => parseInt(v));
|
||||
// GitHub Copilot requires VS Code version 1.92 or higher
|
||||
if (version[0] < 1 || (version[0] === 1 && version[1] < 92)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -198,8 +203,8 @@ export class Copilot {
|
||||
*/
|
||||
private static async getModel() {
|
||||
const [model] = await lm.selectChatModels({
|
||||
vendor: 'copilot'
|
||||
// family: 'gpt-4'
|
||||
vendor: 'copilot',
|
||||
family: Settings.get<string>(SETTING_COPILOT_FAMILY) || 'gpt-3.5-turbo'
|
||||
});
|
||||
|
||||
return model;
|
||||
|
||||
@@ -9,8 +9,6 @@ import {
|
||||
DefaultFields,
|
||||
DEFAULT_CONTENT_TYPE_NAME,
|
||||
ExtensionState,
|
||||
SETTING_SEO_DESCRIPTION_FIELD,
|
||||
SETTING_SEO_TITLE_FIELD,
|
||||
SETTING_DATE_FORMAT
|
||||
} from '../constants';
|
||||
import { Page } from '../dashboardWebView/models';
|
||||
@@ -25,7 +23,7 @@ import {
|
||||
Notifications,
|
||||
Settings
|
||||
} from '../helpers';
|
||||
import { existsAsync } from '../utils';
|
||||
import { existsAsync, getDescriptionField, getTitleField } from '../utils';
|
||||
import { Article, Cache } from '../commands';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
@@ -183,10 +181,8 @@ export class PagesParser {
|
||||
if (article?.data) {
|
||||
const wsFolder = Folders.getWorkspaceFolder();
|
||||
|
||||
const titleField = (Settings.get(SETTING_SEO_TITLE_FIELD) as string) || DefaultFields.Title;
|
||||
|
||||
const descriptionField =
|
||||
(Settings.get(SETTING_SEO_DESCRIPTION_FIELD) as string) || DefaultFields.Description;
|
||||
const titleField = getTitleField();
|
||||
const descriptionField = getDescriptionField();
|
||||
|
||||
const dateField =
|
||||
(await ArticleHelper.getPublishDateField(article)) || DefaultFields.PublishingDate;
|
||||
|
||||
@@ -9,9 +9,6 @@ import { TaxonomyType } from '../models';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { LocalizationKey } from '../localization';
|
||||
|
||||
const AI_URL = WEBSITE_LINKS.api.ai;
|
||||
// const AI_URL = 'http://localhost:3000/api/ai';
|
||||
|
||||
export class SponsorAi {
|
||||
/**
|
||||
* Get title suggestions from the AI
|
||||
@@ -28,19 +25,22 @@ export class SponsorAi {
|
||||
}, 10000);
|
||||
const signal = controller.signal;
|
||||
|
||||
const response = await fetch(`${AI_URL}/title`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
accept: 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
title: title,
|
||||
token: token,
|
||||
nrOfCharacters: Settings.get<number>(SETTING_SEO_TITLE_LENGTH) || 60
|
||||
}),
|
||||
signal: signal as any
|
||||
});
|
||||
const response = await fetch(
|
||||
`${WEBSITE_LINKS.api.baseUrl}${WEBSITE_LINKS.api.endpoints.ai.title}`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
accept: 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
title: title,
|
||||
token: token,
|
||||
nrOfCharacters: Settings.get<number>(SETTING_SEO_TITLE_LENGTH) || 60
|
||||
}),
|
||||
signal: signal as any
|
||||
}
|
||||
);
|
||||
clearTimeout(timeout);
|
||||
|
||||
const data: string[] = await response.json();
|
||||
@@ -66,20 +66,23 @@ export class SponsorAi {
|
||||
articleContent = articleContent.substring(0, 2000);
|
||||
}
|
||||
|
||||
const response = await fetch(`${AI_URL}/description`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
accept: 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
title: title,
|
||||
content: articleContent,
|
||||
token: token,
|
||||
nrOfCharacters: Settings.get<number>(SETTING_SEO_DESCRIPTION_LENGTH) || 160
|
||||
}),
|
||||
signal: signal as any
|
||||
});
|
||||
const response = await fetch(
|
||||
`${WEBSITE_LINKS.api.baseUrl}${WEBSITE_LINKS.api.endpoints.ai.description}`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
accept: 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
title: title,
|
||||
content: articleContent,
|
||||
token: token,
|
||||
nrOfCharacters: Settings.get<number>(SETTING_SEO_DESCRIPTION_LENGTH) || 160
|
||||
}),
|
||||
signal: signal as any
|
||||
}
|
||||
);
|
||||
clearTimeout(timeout);
|
||||
|
||||
const data: string = await response.text();
|
||||
@@ -129,15 +132,18 @@ export class SponsorAi {
|
||||
taxonomy: optionsString
|
||||
});
|
||||
|
||||
const response = await fetch(`${AI_URL}/taxonomy`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
accept: 'application/json'
|
||||
},
|
||||
body,
|
||||
signal: signal as any
|
||||
});
|
||||
const response = await fetch(
|
||||
`${WEBSITE_LINKS.api.baseUrl}${WEBSITE_LINKS.api.endpoints.ai.taxonomy}`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
accept: 'application/json'
|
||||
},
|
||||
body,
|
||||
signal: signal as any
|
||||
}
|
||||
);
|
||||
clearTimeout(timeout);
|
||||
|
||||
if (!response.ok) {
|
||||
|
||||
5
src/utils/getDescriptionField.ts
Normal file
5
src/utils/getDescriptionField.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { DefaultFields, SETTING_SEO_DESCRIPTION_FIELD } from '../constants';
|
||||
import { Settings } from '../helpers';
|
||||
|
||||
export const getDescriptionField = () =>
|
||||
Settings.get<string>(SETTING_SEO_DESCRIPTION_FIELD) || DefaultFields.Description;
|
||||
21
src/utils/getExtensibilityScripts.ts
Normal file
21
src/utils/getExtensibilityScripts.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Uri, Webview } from 'vscode';
|
||||
import { Folders } from '../commands';
|
||||
import { SETTING_EXTENSIBILITY_SCRIPTS } from '../constants';
|
||||
import { Settings } from '../helpers';
|
||||
|
||||
export const getExtensibilityScripts = (webview: Webview) => {
|
||||
const extensibilityScripts = Settings.get<string[]>(SETTING_EXTENSIBILITY_SCRIPTS) || [];
|
||||
|
||||
const scriptsToLoad: string[] = [];
|
||||
for (const script of extensibilityScripts) {
|
||||
if (script.startsWith('https://')) {
|
||||
scriptsToLoad.push(script);
|
||||
} else {
|
||||
const absScriptPath = Folders.getAbsFilePath(script);
|
||||
const scriptUri = webview.asWebviewUri(Uri.file(absScriptPath));
|
||||
scriptsToLoad.push(scriptUri.toString());
|
||||
}
|
||||
}
|
||||
|
||||
return scriptsToLoad;
|
||||
};
|
||||
5
src/utils/getTitleField.ts
Normal file
5
src/utils/getTitleField.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { DefaultFields, SETTING_SEO_TITLE_FIELD } from '../constants';
|
||||
import { Settings } from '../helpers';
|
||||
|
||||
export const getTitleField = () =>
|
||||
Settings.get<string>(SETTING_SEO_TITLE_FIELD) || DefaultFields.Title;
|
||||
@@ -5,10 +5,14 @@ export * from './existsAsync';
|
||||
export * from './fetchWithTimeout';
|
||||
export * from './fieldWhenClause';
|
||||
export * from './flattenObjectKeys';
|
||||
export * from './getDescriptionField';
|
||||
export * from './getExtensibilityScripts';
|
||||
export * from './getLocalizationFile';
|
||||
export * from './getTitleField';
|
||||
export * from './ignoreMsgCommand';
|
||||
export * from './isWindows';
|
||||
export * from './joinUrl';
|
||||
export * from './lstatAsync';
|
||||
export * from './mkdirAsync';
|
||||
export * from './readFileAsync';
|
||||
export * from './readdirAsync';
|
||||
|
||||
4
src/utils/lstatAsync.ts
Normal file
4
src/utils/lstatAsync.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { promisify } from 'util';
|
||||
import { lstat as lstatCb } from 'fs';
|
||||
|
||||
export const lstatAsync = promisify(lstatCb);
|
||||
Reference in New Issue
Block a user