Create a plugin
Build a Review counter panel: one button marks another checked item, the other resets the counter. The example keeps state in the open panel and sends no requests.
You need GrigDesk with support for the v1 manifest. This panel uses ready-to-run JavaScript; no server, bundler or npm dependencies are needed.
Prepare the directory and manifest
Create a separate first-plugin directory outside the application's source tree. Save this as plugin.json in its root:
{
"id": "first-plugin",
"api": 1,
"name": "Счётчик проверок",
"version": "1.0.0",
"description": "Учебная панель со счётчиком проверенных пунктов",
"icon": "assets/icon.png",
"category": "dev",
"entrypoints": {
"web": {
"dir": "ui",
"entry": "panel.js",
"css": ["panel.css"],
"locales": { "ru": "locales/ru.json", "en": "locales/en.json" }
}
},
"contributes": {
"panels": [{ "title": "Счётчик проверок", "group": "tools", "order": 50 }]
},
"install": { "npm": [] }
}Create assets, ui/locales and docs directories. Download the example icon and save it as assets/icon.png. Replace it with your own PNG/JPEG/WebP icon later. The id must be unique within your installation.
Add the panel
Save this as ui/panel.js:
import { h, ref } from 'vue';
import { UiButton } from '@grigdesk/ui';
export default {
props: ['context', 'active', 'compact', 'presentation'],
setup(props) {
const count = ref(0);
return () => h('section', { class: 'first-plugin' }, [
h('h2', props.context.t('title')),
h('p', { role: 'status' }, props.context.t('count', { count: count.value })),
h(UiButton, {
onClick: () => { count.value += 1; },
}, () => props.context.t('add')),
h(UiButton, {
disabled: count.value === 0,
onClick: () => { count.value = 0; },
}, () => props.context.t('reset')),
]);
},
};h creates elements without a template compiler. Vue and UiButton come from the GrigDesk window; do not include their implementations in the package. Each panel instance has its own count.
Save the styles as ui/panel.css:
.first-plugin {
display: grid;
align-content: start;
justify-items: start;
gap: 16px;
padding: 20px;
}
.first-plugin h2,
.first-plugin p {
margin: 0;
}Selectors are scoped to .first-plugin. Shared application UI provides button styling, focus and theme colors.
Add translations and documentation
Save both dictionaries at these paths:
{
"title": "Счётчик проверок",
"count": "Проверено пунктов: {count}",
"add": "Отметить ещё один",
"reset": "Сбросить"
}{
"title": "Review counter",
"count": "Items checked: {count}",
"add": "Check one more",
"reset": "Reset"
}The panel calls props.context.t while rendering. Changing the language updates labels without losing the counter. Likewise, do not copy settings and language once at load time if the interface should follow later changes.
Describe the purpose and limits in docs/README.md. For example:
# Счётчик проверок
Учебная панель: отмечает проверенные пункты и сбрасывает счётчик.
Состояние хранится только в экземпляре панели. После размонтирования
или перезагрузки окна оно сбрасывается. Серверных запросов, файлов и внешних сервисов нет.
Для установки выберите тег v1.0.0, затем включите плагин и примените изменение.
Панель открывается в группе «Инструменты».When the guide grows, keep an index here linking to neighboring documents.
Install and verify
Initialize Git inside your plugin directory, add the prepared files, create a commit and tag:
git init
git add plugin.json assets ui docs
git commit -m "Initial plugin"
git tag -a v1.0.0 -m "First release"For a check on the same machine, use Install from Git… with file:///absolute/path/to/first-plugin. If GrigDesk runs on a remote server, the path refers to that server. Alternatively, push the repository and tag to a Git host accessible from the server.
Follow installation, enable the plugin and apply the change. The panel appears in Tools at /ext/first-plugin; its manifest uses the Russian name “Счётчик проверок”.
Check the result:
- The button increments the counter; reset returns it to zero.
- Buttons work from the keyboard; reset is disabled at zero.
- Switching RU/EN changes labels and preserves the value.
- The panel fits a narrow window and follows light and dark themes.
- Unmounting the panel or reloading the window resets the counter.
For the next release, change version, create a new commit and tag such as v1.0.1, and check the update. Keep development sources separate from GrigDesk's installed copy.
When you need a build
Use your own project's bundler for Vue SFC and TypeScript. Compile .vue templates ahead of time: the window has no runtime template compiler. Keep vue and @grigdesk/ui external, emit CSS separately and include ready-to-run files in the installable repository.
The installer does not build sources. npm preparation installs production dependencies with scripts disabled. Such dependencies require package.json, a v2/v3 lockfile and a correct install.npm declaration. Local file: dependencies, workspaces and packaged .npmrc files are not supported.
To obtain types from a GrigDesk checkout, write them to an empty directory outside its source tree:
npm --prefix web run build:plugin-types -- --out-dir /absolute/path/to/sdkIn your development project, install that directory as a devDependency. Use import type from @grigdesk/plugin-types, /web and /server. For @grigdesk/ui type checking, map TypeScript paths to node_modules/@grigdesk/plugin-types/ui.d.ts. The types package is a snapshot of a GrigDesk version; rebuild it after application updates. Keep local SDK dev dependencies in the development project and give the installer a separate, ready-to-run package.