From 677951d65d3ab74b7104f61059057a8c629d10a9 Mon Sep 17 00:00:00 2001
From: Woodii <33593572+Woodii1998@users.noreply.github.com>
Date: Mon, 28 Apr 2025 14:35:21 +0800
Subject: [PATCH 1/3] feat: update catalogue (#286)
---
src/components/homeCatalogue/catalogue.ts | 18 ++++++++++--------
src/components/homeCatalogue/index.tsx | 5 ++++-
2 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/src/components/homeCatalogue/catalogue.ts b/src/components/homeCatalogue/catalogue.ts
index c6c49ef6d..052b58c8e 100644
--- a/src/components/homeCatalogue/catalogue.ts
+++ b/src/components/homeCatalogue/catalogue.ts
@@ -1,6 +1,6 @@
import { translate } from '@docusaurus/Translate';
-export const CATALOGUE = [
+export const CATALOGUE = (local: string) => [
{
header: { title: translate({ id: 'home.catalogue.getting-started', message: '新手入门' }) },
docs: [
@@ -52,13 +52,15 @@ export const CATALOGUE = [
docLink: '/viz/frame-rate-optimization',
title: translate({ id: 'home.catalogue.frame-rate-optimization', message: '帧率优化选项' }),
},
- ...(typeof process !== 'undefined' && process.env.DOCUSAURUS_CURRENT_LOCALE === 'zh' ? [
- { docLink: '/category/extensions', title: translate({ id: 'home.catalogue.extensions', message: '插件' }) },
- {
- docLink: '/viz/message-schemas',
- title: translate({ id: 'home.catalogue.message-schemas', message: '消息架构' }),
- },
- ] : []),
+ ...(local === 'zh'
+ ? [
+ { docLink: '/category/extensions', title: translate({ id: 'home.catalogue.extensions', message: '插件' }) },
+ {
+ docLink: '/viz/message-schemas',
+ title: translate({ id: 'home.catalogue.message-schemas', message: '消息架构' }),
+ },
+ ]
+ : []),
],
},
{
diff --git a/src/components/homeCatalogue/index.tsx b/src/components/homeCatalogue/index.tsx
index 59caa4821..a169dc17d 100644
--- a/src/components/homeCatalogue/index.tsx
+++ b/src/components/homeCatalogue/index.tsx
@@ -1,6 +1,7 @@
import React from 'react';
import { CATALOGUE } from './catalogue';
import Link from '@docusaurus/Link';
+import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
interface DocSlugProps {
title: string;
@@ -53,9 +54,11 @@ function Card({ catalogue }: { catalogue: { header: { title: string }; docs: Doc
}
export default function HomeCatalogue() {
+ const { i18n } = useDocusaurusContext();
+
return (
- {CATALOGUE.map((item, index) => (
+ {CATALOGUE(i18n.currentLocale).map((item, index) => (
))}
From 8a4ceb6c38e59446f6691a5c122b51b84d9326ab Mon Sep 17 00:00:00 2001
From: Yujing Zheng
Date: Mon, 12 May 2025 20:39:42 +0800
Subject: [PATCH 2/3] Add Translations for Custom Panels and some broken links
fix (#288)
* feat: add dev script to package.json and update links in documentation
- Added a new "dev" script to package.json for easier local development.
- Updated links in the device collector and data diagnosis documentation for better navigation.
- Ensured consistent formatting in the device collector documentation.
* Fix absolute links in cn changelog
* create project broken link
* add translations
* translate message converters
* translate topic aliases
* translate other docs
* fix a couple files that did not translate to english
* Add more translations
---
docs/device/4-device-collector.md | 6 +-
docs/use-case/data-diagnosis/2-get-started.md | 4 +-
.../5-api/6-other/8-variable-value.md | 2 -
.../use-case/data-diagnosis/2-get-started.md | 5 +-
.../viz/8-extensions/1-introduction.md | 63 ++
.../viz/8-extensions/2-local-development.md | 24 +
...rters-to-display-3d-markers-in-3d-panel.md | 162 +++++
.../3-best-practices/2-custom-panel.md | 398 +++++++++++
.../3-best-practices/_category_.json | 9 +
.../3-best-practices/img/3dPanel.png | Bin 0 -> 338097 bytes
.../img/customRawMessageExtensionList.png | Bin 0 -> 149585 bytes
.../img/customRawMessagePanel.png | Bin 0 -> 328304 bytes
.../img/customRawMessagePanelList.png | Bin 0 -> 322918 bytes
.../3-best-practices/img/extensionList.png | Bin 0 -> 259680 bytes
.../4-guides/1-create-custom-panel.md | 59 ++
.../4-guides/2-create-message-converter.md | 79 +++
.../3-optimize-extension-performance.md | 45 ++
.../viz/8-extensions/4-guides/_category_.json | 9 +
.../viz/8-extensions/5-api/1-introduction.md | 13 +
.../2-entry-point/1-extension-context.md | 91 +++
.../5-api/2-entry-point/2-extension-module.md | 42 ++
.../5-api/2-entry-point/_category_.json | 9 +
.../1-extension-panel-registration.md | 43 ++
.../10-settings-tree-fields.md | 11 +
.../11-settings-tree-field-value.md | 216 ++++++
.../3-custom-panels/12-settings-tree-node.md | 154 ++++
.../13-settings-tree-node-action.md | 11 +
.../14-settings-tree-node-action-divider.md | 21 +
.../15-settings-tree-node-action-item.md | 59 ++
.../16-subscribe-message-range-args.md | 133 ++++
.../5-api/3-custom-panels/17-subscription.md | 75 ++
.../5-api/3-custom-panels/2-layout-actions.md | 110 +++
.../3-panel-extension-context.md | 666 ++++++++++++++++++
.../5-api/3-custom-panels/4-render-state.md | 151 ++++
.../5-api/3-custom-panels/5-settings-icon.md | 69 ++
.../5-api/3-custom-panels/6-settings-tree.md | 94 +++
.../3-custom-panels/7-settings-tree-action.md | 38 +
.../8-settings-tree-children.md | 11 +
.../3-custom-panels/9-settings-tree-field.md | 80 +++
.../5-api/3-custom-panels/_category_.json | 9 +
.../1-register-message-converter-args.md | 53 ++
.../4-message-converters/_category_.json | 9 +
.../5-api/5-topic-aliases/1-base-topic.md | 25 +
.../5-api/5-topic-aliases/2-topic-alias.md | 23 +
.../5-topic-aliases/3-topic-alias-function.md | 21 +
.../5-api/5-topic-aliases/_category_.json | 9 +
.../5-api/6-other/1-app-setting-value.md | 11 +
.../8-extensions/5-api/6-other/2-immutable.md | 16 +
.../5-api/6-other/3-message-event.md | 90 +++
.../5-api/6-other/4-parameter-value.md | 11 +
.../viz/8-extensions/5-api/6-other/5-time.md | 29 +
.../viz/8-extensions/5-api/6-other/6-topic.md | 49 ++
.../5-api/6-other/7-variable-struct.md | 15 +
.../5-api/6-other/8-variable-value.md | 9 +
.../5-api/6-other/_category_.json | 9 +
.../viz/8-extensions/5-api/_category_.json | 9 +
.../current/viz/8-extensions/_category_.json | 9 +
.../viz/9-message-schemas/_category_.json | 9 +
.../viz/9-message-schemas/arrow-primitive.md | 37 +
.../viz/9-message-schemas/built-in types.md | 60 ++
.../9-message-schemas/camera-calibration.md | 88 +++
.../9-message-schemas/circle-annotation.md | 42 ++
.../current/viz/9-message-schemas/color.md | 40 ++
.../viz/9-message-schemas/compressed-image.md | 38 +
.../viz/9-message-schemas/compressed-video.md | 52 ++
.../viz/9-message-schemas/cube-primitive.md | 30 +
.../9-message-schemas/cylinder-primitive.md | 32 +
.../viz/9-message-schemas/enum-line-type.md | 19 +
.../viz/9-message-schemas/enum-log-level.md | 22 +
.../9-message-schemas/enum-numeric-type.md | 21 +
.../enum-points-annotation-type.md | 17 +
.../enum-position-covariance-type.md | 16 +
.../enum-scene-entity-deletion-type.md | 14 +
.../viz/9-message-schemas/frame-transform.md | 36 +
.../viz/9-message-schemas/frame-transforms.md | 24 +
.../current/viz/9-message-schemas/geo-json.md | 28 +
.../current/viz/9-message-schemas/grid.md | 40 ++
.../9-message-schemas/image-annotations.md | 34 +
.../viz/9-message-schemas/introduction.md | 88 +++
.../viz/9-message-schemas/key-value-pair.md | 29 +
.../viz/9-message-schemas/laser-scan.md | 34 +
.../viz/9-message-schemas/line-primitive.md | 39 +
.../viz/9-message-schemas/location-fix.md | 34 +
.../current/viz/9-message-schemas/log.md | 33 +
.../viz/9-message-schemas/model-primitive.md | 34 +
.../9-message-schemas/packed-element-field.md | 30 +
.../current/viz/9-message-schemas/point-2.md | 29 +
.../current/viz/9-message-schemas/point-3.md | 30 +
.../viz/9-message-schemas/point-cloud.md | 33 +
.../9-message-schemas/points-annotation.md | 38 +
.../viz/9-message-schemas/pose-in-frame.md | 30 +
.../current/viz/9-message-schemas/pose.md | 29 +
.../viz/9-message-schemas/poses-in-frame.md | 30 +
.../viz/9-message-schemas/quaternion.md | 31 +
.../viz/9-message-schemas/raw-image.md | 38 +
.../scene-entity-deletion.md | 30 +
.../viz/9-message-schemas/scene-entity.md | 41 ++
.../viz/9-message-schemas/scene-update.md | 29 +
.../viz/9-message-schemas/sphere-primitive.md | 30 +
.../viz/9-message-schemas/text-annotation.md | 37 +
.../viz/9-message-schemas/text-primitive.md | 33 +
.../triangle-list-primitive.md | 36 +
.../current/viz/9-message-schemas/vector-2.md | 29 +
.../current/viz/9-message-schemas/vector-3.md | 30 +
.../changelog.md | 2 +-
package.json | 3 +-
src/pages/changelog.md | 6 +-
107 files changed, 4966 insertions(+), 16 deletions(-)
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/1-introduction.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/2-local-development.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/3-best-practices/1-using-message-converters-to-display-3d-markers-in-3d-panel.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/3-best-practices/2-custom-panel.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/3-best-practices/_category_.json
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/3-best-practices/img/3dPanel.png
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/3-best-practices/img/customRawMessageExtensionList.png
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/3-best-practices/img/customRawMessagePanel.png
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/3-best-practices/img/customRawMessagePanelList.png
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/3-best-practices/img/extensionList.png
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/4-guides/1-create-custom-panel.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/4-guides/2-create-message-converter.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/4-guides/3-optimize-extension-performance.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/4-guides/_category_.json
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/1-introduction.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/2-entry-point/1-extension-context.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/2-entry-point/2-extension-module.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/2-entry-point/_category_.json
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/3-custom-panels/1-extension-panel-registration.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/3-custom-panels/10-settings-tree-fields.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/3-custom-panels/11-settings-tree-field-value.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/3-custom-panels/12-settings-tree-node.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/3-custom-panels/13-settings-tree-node-action.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/3-custom-panels/14-settings-tree-node-action-divider.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/3-custom-panels/15-settings-tree-node-action-item.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/3-custom-panels/16-subscribe-message-range-args.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/3-custom-panels/17-subscription.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/3-custom-panels/2-layout-actions.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/3-custom-panels/3-panel-extension-context.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/3-custom-panels/4-render-state.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/3-custom-panels/5-settings-icon.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/3-custom-panels/6-settings-tree.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/3-custom-panels/7-settings-tree-action.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/3-custom-panels/8-settings-tree-children.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/3-custom-panels/9-settings-tree-field.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/3-custom-panels/_category_.json
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/4-message-converters/1-register-message-converter-args.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/4-message-converters/_category_.json
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/5-topic-aliases/1-base-topic.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/5-topic-aliases/2-topic-alias.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/5-topic-aliases/3-topic-alias-function.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/5-topic-aliases/_category_.json
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/6-other/1-app-setting-value.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/6-other/2-immutable.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/6-other/3-message-event.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/6-other/4-parameter-value.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/6-other/5-time.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/6-other/6-topic.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/6-other/7-variable-struct.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/6-other/8-variable-value.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/6-other/_category_.json
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/5-api/_category_.json
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/_category_.json
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/_category_.json
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/arrow-primitive.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/built-in types.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/camera-calibration.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/circle-annotation.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/color.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/compressed-image.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/compressed-video.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/cube-primitive.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/cylinder-primitive.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/enum-line-type.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/enum-log-level.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/enum-numeric-type.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/enum-points-annotation-type.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/enum-position-covariance-type.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/enum-scene-entity-deletion-type.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/frame-transform.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/frame-transforms.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/geo-json.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/grid.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/image-annotations.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/introduction.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/key-value-pair.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/laser-scan.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/line-primitive.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/location-fix.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/log.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/model-primitive.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/packed-element-field.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/point-2.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/point-3.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/point-cloud.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/points-annotation.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/pose-in-frame.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/pose.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/poses-in-frame.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/quaternion.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/raw-image.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/scene-entity-deletion.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/scene-entity.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/scene-update.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/sphere-primitive.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/text-annotation.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/text-primitive.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/triangle-list-primitive.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/vector-2.md
create mode 100644 i18n/en/docusaurus-plugin-content-docs/current/viz/9-message-schemas/vector-3.md
diff --git a/docs/device/4-device-collector.md b/docs/device/4-device-collector.md
index 6306fd6d8..2f8364152 100644
--- a/docs/device/4-device-collector.md
+++ b/docs/device/4-device-collector.md
@@ -31,17 +31,17 @@ sidebar_position: 4

-## 数采规则格式详解
+## 数采规则格式详解 {#device-collector-format}
数采规则主要对 5 个模块进行设置:
| 模块名称 | 功能描述 |
| --------------------------- | -------------------------------------------------------------- |
-| 数据收集器设置(collector) | 完成数据采集后,是否删除数采客户端在设备端生成的缓存数据 |
+| 数据收集器设置(collector) | 完成数据采集后,是否删除数采客户端在设备端生成的缓存数据 |
| 存储设置(mod) | 设备 ID 存放位置;监听目录;客户端初始化监听时间范围;采集目录 |
| 设备事件属性(device) | 事件的属性值 |
| 规则触发话题(topic) | 规则触发话题 |
-| 更新设置(updater) | 数采客户端是否开启自动更新 |
+| 更新设置(updater) | 数采客户端是否开启自动更新 |
示例模板如下:
diff --git a/docs/use-case/data-diagnosis/2-get-started.md b/docs/use-case/data-diagnosis/2-get-started.md
index 0a10172bd..e045e336b 100644
--- a/docs/use-case/data-diagnosis/2-get-started.md
+++ b/docs/use-case/data-diagnosis/2-get-started.md
@@ -14,7 +14,7 @@ sidebar_position: 2
1. 请准备好一台设备
-2. 请创建名为 auto-upload 的项目,详情参见[创建新项目](https://docs.coscene.cn/docs/recipes/project)。
+2. 请创建名为 auto-upload 的项目
3. 请确认你在 coScene 的组织角色为「管理员」。若不是管理员,请联系组织管理员更新你的组织角色。
@@ -96,7 +96,7 @@ sidebar_position: 2
enabled: false
```
- \*更多配置参见[数采规则格式](https://docs.coscene.cn/docs/recipes/device/device-collector/#%E6%95%B0%E9%87%87%E8%A7%84%E5%88%99%E6%A0%BC%E5%BC%8F)
+ 更多配置参见[数采规则格式](../../device/4-device-collector.md#device-collector-format)
3. 点击【保存编辑】按钮
diff --git a/docs/viz/8-extensions/5-api/6-other/8-variable-value.md b/docs/viz/8-extensions/5-api/6-other/8-variable-value.md
index 10f03cc42..3acf2f772 100644
--- a/docs/viz/8-extensions/5-api/6-other/8-variable-value.md
+++ b/docs/viz/8-extensions/5-api/6-other/8-variable-value.md
@@ -7,5 +7,3 @@ sidebar_position: 8
```typescript
type VariableValue = undefined | boolean | number | string | VariableValue[] | {};
```
-
-变量的有效类型
\ No newline at end of file
diff --git a/i18n/en/docusaurus-plugin-content-docs/current/use-case/data-diagnosis/2-get-started.md b/i18n/en/docusaurus-plugin-content-docs/current/use-case/data-diagnosis/2-get-started.md
index d0bb244ee..2029e9d30 100644
--- a/i18n/en/docusaurus-plugin-content-docs/current/use-case/data-diagnosis/2-get-started.md
+++ b/i18n/en/docusaurus-plugin-content-docs/current/use-case/data-diagnosis/2-get-started.md
@@ -11,7 +11,7 @@ Using the following scenario as an example, let's setup your automatic data coll
## Prerequisites
1. Have a device ready.
-2. Create a project named `auto-upload`. See [Cerate New Project](https://docs.coscene.cn/en/docs/recipes/project) for details.
+2. Create a project named `auto-upload`.
3. Make sure your role in the coScene organization is "Administrator". If you're not an administrator, contact your organizational admin to update your role.

@@ -191,6 +191,3 @@ Using the following scenario as an example, let's setup your automatic data coll
2. View the automatically created record, and check the data uploaded in the record.

-
-
-
diff --git a/i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/1-introduction.md b/i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/1-introduction.md
new file mode 100644
index 000000000..e03aa003f
--- /dev/null
+++ b/i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/1-introduction.md
@@ -0,0 +1,63 @@
+---
+sidebar_position: 1
+---
+
+# Extensions Introduction
+
+Extend visualization capabilities through custom extensions to better support your team's unique workflows. Build custom panels, convert custom messages into visualization-supported schemas, and create aliases for topic names to facilitate visualization.
+
+Once you develop and install extensions, you can enable them in the application settings to display all available and installed extensions.
+
+## Custom Panels
+
+While visualization provides a set of built-in panels for robot data visualization and debugging, many users have domain-specific requirements that our out-of-the-box product cannot meet.
+
+Custom panel extensions allow you to build complete panels. Custom panels can subscribe to messages on various topics, publish and receive messages, and display message information in a form that best suits your workflow.
+
+Custom panels are ideal when your visualization or interaction requirements are customized and not easily addressed through built-in panels.
+
+### Links and Resources
+
+- Guide: Creating Custom Panels
+- Building Custom Panel Extensions (React)
+
+## Message Converters
+
+Message converter extensions allow you to transform messages from one schema to another. By converting messages to schemas supported by visualization, you can inspect them using visualization's built-in visualization features. For example, you can use a message converter to transform custom GPS messages into foxglove.LocationFix messages for visualization in the map panel.
+
+> Note: Message converters only run on-demand when panels subscribe to topics.
+
+### Links and Resources
+
+- Guide: Creating Message Converters
+- Writing Message Converter Extensions (Map Panel)
+- Writing Message Converter Extensions (3D Panel)
+
+## Topic Aliases
+
+Topic alias extensions allow you to alias topics from your data source to new topics. Visualization panels can subscribe to both aliased topics and topics from the original data source.
+
+## Writing Extensions
+
+You can write extensions using JavaScript or TypeScript and package them into `.coe` files. You can distribute these files privately within your organization or publicly through our registry (in development) - installing extensions through the registry is only supported in the desktop application. A single extension can contain multiple panels or converters.
+
+coScene provides a set of starter templates and commands in the [create-coscene-extension](https://github.com/coscene-io/create-coscene-extension) package to simplify extension writing.
+
+Requirements:
+
+- Node.js 14+
+
+To set up your extension project, navigate to the directory where you want your source code to reside, and run the following command in a terminal window:
+
+```
+npm init coscene-extension@latest my-extension-name
+```
+
+This will set up the extension directory structure. Your extension entry point is the `index.ts` file.
+
+The entry point script must export an ExtensionModule — a function named `activate` that accepts a single `ExtensionContext` parameter.
+
+## API Reference
+
+- [ExtensionContext](/docs/viz/extensions/api/entry-point/extension-context)
+- @coscene/coscene-extension
diff --git a/i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/2-local-development.md b/i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/2-local-development.md
new file mode 100644
index 000000000..47356df88
--- /dev/null
+++ b/i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/2-local-development.md
@@ -0,0 +1,24 @@
+---
+sidebar_position: 2
+---
+
+# Local Development
+
+Build and test your custom visualization extensions locally before publishing.
+
+## Installation
+
+To build and install your extension to the local coStudio extensions folder, run `npm run local-install`. This will create a folder under your user home directory (e.g., `~/.coStudio/extensions/unknown.myExtensionName-0.0.0`) containing your compiled extension.
+
+Open the latest version of the coStudio desktop application. You should now see `myExtensionName` in the list of installed extensions in the application settings.
+
+After installation, you should be able to open the "Add Panel" menu and see an option called `ExamplePanel`. You have successfully loaded your first visualization extension!
+
+(🏗️ Work in progress, expected to launch in May 2025)
+To install local extensions on the web application, you must first package your extension, then drag and drop the `.coe` file onto an open visualization page. You can also open `.coe` files in the desktop application by dragging and dropping or double-clicking.
+
+## Development
+
+Every time you make changes to your extension, you must run `npm run local-install` to build it into the local extensions folder.
+
+Reload or restart coStudio to execute the latest version of your extension code in the application. Alternatively, you can simply run `npm run build` to confirm that your code compiles without installing it locally.
diff --git a/i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/3-best-practices/1-using-message-converters-to-display-3d-markers-in-3d-panel.md b/i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/3-best-practices/1-using-message-converters-to-display-3d-markers-in-3d-panel.md
new file mode 100644
index 000000000..5a9f67efe
--- /dev/null
+++ b/i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/3-best-practices/1-using-message-converters-to-display-3d-markers-in-3d-panel.md
@@ -0,0 +1,162 @@
+---
+sidebar_position: 1
+---
+
+# Using Message Converters to Display 3D Markers in 3D Panel
+
+By writing your own message converter, you can use coScene's existing panels to visualize your custom messages, even if these message definitions are not supported by the existing panels.
+
+## Why Use Message Converters
+
+While you could build a custom panel every time you want to visualize certain specific data, writing a message converter can save you a lot of time and effort. Message converters transform data into supported formats, allowing existing panels to handle the visualization without having to build another panel from scratch.
+
+## Our Goal
+
+We will create a message converter that transforms custom `my.Marker` messages into `foxglove.SceneUpdate` messages, then use the 3D panel to display these markers. You can download the [example mcap file](https://download.coscene.cn/assets/bags/example.mcap) for this tutorial.
+
+## Prerequisites
+
+Before we begin, you should be familiar with or have installed:
+
+- Basic robotics concepts
+- Basic usage of coScene visualization features
+- [Basic JavaScript/TypeScript syntax](https://www.typescriptlang.org/docs/handbook/basic-types.html)
+- [Basic usage of frontend package managers like npm](https://docs.npmjs.com/)
+- [Node.js version 14 or higher installed on your current device](https://nodejs.org/en/download/)
+
+## Initialize the Project
+
+Create a project using [create-coscene-extension](https://github.com/coscene-io/create-coscene-extension):
+
+```bash
+npm init coscene-extension@latest mySceneUpdateConverter
+```
+
+This command will create a `mySceneUpdateConverter` directory containing some template source code.
+
+## Write the Converter
+
+src/index.ts is the entry point for the plugin source code. It exports an `activate` function that accepts a single parameter of type [`ExtensionContext`](/docs/viz/extensions/api/entry-point/extension-context).
+
+First, let's add the `@foxglove/schemas` package to our project. `@foxglove/schemas` is foxglove's schema definition library, where you can find all foxglove-supported schema definitions:
+
+```bash
+npm install @foxglove/schemas
+```
+
+Then, open the `src/index.ts` file and import the following packages:
+
+```ts
+// Import coScene's plugin context
+import { ExtensionContext } from '@coscene/extension';
+// Import foxglove's schema definitions
+import { CubePrimitive, SceneUpdate } from '@foxglove/schemas';
+// Import foxglove's time type definition
+import { Time } from '@foxglove/schemas/schemas/typescript/Time';
+```
+
+And declare our custom `my.Marker` message type:
+
+```ts
+// Declare our custom `my.Marker` message type
+type DetectedObject = {
+ position: [number, number, number];
+ markerType: 'adult' | 'car' | 'truck';
+ scale: [number, number, number];
+ timestamp: Time;
+ frameId: string;
+};
+```
+
+To register the message converter, we need to call the `registerMessageConverter` function from `extensionContext`. The `registerMessageConverter` function requires three parameters:
+
+- fromSchemaName: The message type defined in mcap that needs to be converted
+- toSchemaName: The target message type after conversion
+- converter: The function that performs the conversion, which accepts the message registered in fromSchemaName. We need to convert the message to the type registered in toSchemaName
+
+```ts
+// Register the message converter
+export function activate(extensionContext: ExtensionContext) {
+ extensionContext.registerMessageConverter({
+ fromSchemaName: 'my.Marker',
+ toSchemaName: 'foxglove.SceneUpdate',
+ converter: (inputMessage: DetectedObject): SceneUpdate => {
+ // Conversion logic from my.Marker to foxglove.SceneUpdate
+ },
+ });
+}
+```
+
+Fill in the converter function to transform `my.Marker` messages into `foxglove.SceneUpdate` messages. We'll display all detected objects as colored cubes:
+
+- Blue for adults
+- Red for cars
+- Green for trucks
+
+```ts
+converter: (inputMessage: DetectedObject): SceneUpdate => {
+ const { position, scale, markerType, timestamp, frameId } = inputMessage;
+ const colorMap = {
+ adult: { r: 0, g: 0, b: 1, a: 1 },
+ car: { r: 1, g: 0, b: 0, a: 1 },
+ truck: { r: 0, g: 1, b: 0, a: 1 },
+ };
+
+ const cubePrimitive: CubePrimitive = {
+ pose: {
+ position: { x: position[0], y: position[1], z: position[2] },
+ orientation: { x: 0, y: 0, z: 0, w: 1 },
+ },
+ size: { x: scale[0], y: scale[1], z: scale[2] },
+ color: colorMap[markerType],
+ };
+
+ const sceneUpdateMessage = {
+ deletions: [],
+ entities: [
+ {
+ id: 'detectedObjects-entities',
+ timestamp,
+ frame_id: frameId,
+ lifetime: { sec: 10, nsec: 0 },
+ frame_locked: false,
+ metadata: [],
+ arrows: [],
+ cubes: [cubePrimitive],
+ spheres: [],
+ cylinders: [],
+ lines: [],
+ triangles: [],
+ texts: [],
+ models: [],
+ },
+ ],
+ };
+
+ return sceneUpdateMessage;
+};
+```
+
+## Test the Plugin
+
+To build and install the plugin for local testing in coStudio, run the following command in the plugin directory:
+
+```bash
+npm run local-install
+```
+
+In coStudio, open the plugin list on the right side, and you'll now see `mySceneUpdateConverter` in the list of installed plugins:
+
+
+Now, open our example mcap file, and you can open the 3D panel to see all detected objects displayed as colored cubes:
+
+
+## Share Your Plugin
+
+To share your plugin with others, you need to package it as a .coe file. To do this, run the following command in the plugin directory:
+
+```bash
+npm run package
+```
+
+You'll find an `unknown.mySceneUpdateConverter-0.0.0.coe` file in the plugin directory. You can distribute this to others, and they can install it in their coStudio by dragging and dropping it.
diff --git a/i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/3-best-practices/2-custom-panel.md b/i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/3-best-practices/2-custom-panel.md
new file mode 100644
index 000000000..f21687852
--- /dev/null
+++ b/i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/3-best-practices/2-custom-panel.md
@@ -0,0 +1,398 @@
+---
+sidebar_position: 2
+---
+
+# Custom Panel
+
+By writing your own panel, you can have more flexible control over the panel's appearance and behavior to meet your specific needs.
+
+## Why Use Custom Panels
+
+Custom panels are very useful when existing panels don't support your visualization needs. You have complete control over the panel's appearance and behavior to meet your specific requirements.
+
+## Our Goal
+
+We will create a custom panel that simulates the original message panel, using [react-json-view](https://github.com/microlinkhq/react-json-view) to display the raw messages for the corresponding topic.
+
+## Before You Begin
+
+Before starting, you need to understand/install some basic concepts/environments:
+
+- Basic robotics concepts
+- Basic usage of coScene visualization features
+- [Basic JS/TS syntax](https://www.typescriptlang.org/docs/handbook/basic-types.html)
+- [Basic React usage](https://react.dev/)
+- [Basic usage of frontend package managers like npm](https://docs.npmjs.com/)
+- [Node.js version 14 or higher installed on your current device](https://nodejs.org/en/download/)
+
+## Initialize Project
+
+Create a project using [create-coscene-extension](https://github.com/coscene-io/create-coscene-extension):
+
+```bash
+npm init coscene-extension@latest custom-raw-message-panel
+```
+
+This command will create a `custom-raw-message-panel` directory containing some template source code.
+
+Then, we need to install some dependencies in our project:
+
+- `@microlink/react-json-view` is a React component for displaying JSON data
+- `immer` is a JavaScript library for handling immutable state
+- `lodash` is a well-known JavaScript utility library that provides many useful functions, including array operations, object operations, etc.
+
+```bash
+npm install @microlink/react-json-view immer lodash
+```
+
+Then we open the `package.json` file and modify the `displayName` and `description` fields to `custom raw message panel`. The modified `package.json` file should look like this:
+
+```json
+{
+ "name": "custom-raw-message-panel",
+ "displayName": "custom raw message panel",
+ "description": "custom raw message panel",
+ ...
+}
+```
+
+## Write Custom Panel
+
+Now open the `custom-raw-message-panel` folder in your chosen editor, then open the `src/index.ts` file. You'll see that the file already registers an example panel as `example-panel`. First, we need to change this example panel's name to `custom-raw-message-panel`. The modified `index.ts` file should look like this:
+
+```ts
+import { ExtensionContext } from '@coscene/extension';
+
+import { initExamplePanel } from './ExamplePanel';
+
+export function activate(extensionContext: ExtensionContext): void {
+ extensionContext.registerPanel({
+ name: 'custom-raw-message-panel',
+ initPanel: initExamplePanel,
+ });
+}
+```
+
+Then we open the `src/ExamplePanel.tsx` file. In the `src/ExamplePanel.tsx` file, you'll see a simple panel component. We need to first explain the code in this file, then modify it according to our needs. This file uses React's state management to track subscribed topics, messages, and their rendering state.
+
+```ts
+function ExamplePanel({ context }: { context: PanelExtensionContext }): JSX.Element {
+ const [topics, setTopics] = useState();
+ const [messages, setMessages] = useState[] | undefined>();
+
+ const [renderDone, setRenderDone] = useState<() => void | undefined>();
+```
+
+In the example, when relevant updates are detected, the `onRender` event will run:
+
+```ts
+useLayoutEffect(() => {
+ context.onRender = (renderState: RenderState, done) => {
+ setRenderDone(() => done);
+ setTopics(renderState.topics);
+ setMessages(renderState.currentFrame);
+ };
+}, [context]);
+```
+
+The onRender function receives the latest panel state:
+
+- `done` is a callback function after the new rendering is complete. When rendering is complete, you need to call the `done` function to indicate that the panel has completed the previous rendering cycle
+- `renderState.topics` is the latest topic list
+- `renderState.currentFrame` contains new messages for subscribed topics
+
+Next, use the `context.watch` function to tell the context which states need to be monitored. When the state changes, it will trigger the `onRender` event. `context.watch` is used to monitor key values in [`RenderState`](/docs/viz/extensions/api/custom-panels/render-state). You can view all monitorable key values from [`RenderState`](/docs/viz/extensions/api/custom-panels/render-state)
+
+```ts
+context.onRender = (renderState: RenderState, done) => {
+ // ...
+};
+// Tell the panel context we care about changes in the _topic_ field in RenderState
+context.watch('topics');
+// Tell the panel context we want to subscribe to messages in the current frame
+context.watch('currentFrame');
+```
+
+Then we need to use the `context.subscribe` function to subscribe to the topic array. Messages from these topics will be populated into `renderState.currentFrame`
+
+```ts
+context.subscribe(['/some/topic']);
+```
+
+Finally, when the panel finishes rendering, we need to call the `renderDone` function to indicate that the panel has completed the previous rendering cycle
+
+```ts
+useEffect(() => {
+ renderDone?.();
+}, [renderDone]);
+```
+
+At the bottom of the function, we can see how to use all this logic to render a table of data source topics and schema names
+
+```ts
+return (
+
+
Welcome to your new extension panel!
+ {/* ... */}
+ {(topics ?? []).map((topic) => (
+ <>
+
{topic.name}
+
{topic.datatype}
+ >
+ ))}
+ {/* ... */}
+
+);
+```
+
+According to our needs, in the settings we need to let users choose the topic to display, and let users choose the theme supported by `@microlink/react-json-view`, indentation, and whether to display data types.
+
+So we need to first define the TypeScript types for settings: State, and the themes supported by `@microlink/react-json-view` `ThemeOptions`.
+
+```ts
+// Themes supported by @microlink/react-json-view
+const ThemeOptions = [
+ 'apathy',
+ 'apathy:inverted',
+ 'ashes',
+ 'bespin',
+ 'brewer',
+ 'bright:inverted',
+ 'bright',
+ 'chalk',
+ 'codeschool',
+ 'colors',
+ 'eighties',
+ 'embers',
+ 'flat',
+ 'google',
+ 'grayscale',
+ 'grayscale:inverted',
+ 'greenscreen',
+ 'harmonic',
+ 'hopscotch',
+ 'isotope',
+ 'marrakesh',
+ 'mocha',
+ 'monokai',
+ 'ocean',
+ 'paraiso',
+ 'pop',
+ 'railscasts',
+ 'rjv-default',
+ 'shapeshifter',
+ 'shapeshifter:inverted',
+ 'solarized',
+ 'summerfruit',
+ 'summerfruit:inverted',
+ 'threezerotwofour',
+ 'tomorrow',
+ 'tube',
+ 'twilight',
+].map((key) => ({ value: key, label: key }));
+
+// This is the type we'll use when rendering the panel and persist to the layout.
+type State = {
+ data: {
+ label: string;
+ topic?: string;
+ visible: boolean;
+ };
+ appearance: {
+ displayDataTypes: boolean;
+ indentWidth: string;
+ theme: string;
+ };
+};
+```
+
+Then we need to use React's `useState` to manage the settings state and declare a function to update the settings state.
+
+```ts
+import { produce } from 'immer';
+import { set } from 'lodash';
+
+// Build our panel state from the context's initialState, filling in any missing values.
+const [state, setState] = useState(() => {
+ const partialState = context.initialState as Partial;
+ return {
+ data: {
+ label: partialState.data?.label ?? 'Data',
+ topic: partialState.data?.topic ?? '/pose',
+ visible: partialState.data?.visible ?? true,
+ },
+ appearance: {
+ displayDataTypes: partialState.appearance?.displayDataTypes ?? true,
+ theme: partialState.appearance?.theme ?? 'rjv-default',
+ indentWidth: partialState.appearance?.indentWidth ?? '2',
+ },
+ };
+});
+
+// Update our state in response to edit operations from the settings panel.
+const actionHandler = useCallback(
+ (action: SettingsTreeAction) => {
+ if (action.action === 'update') {
+ const { path, value } = action.payload;
+
+ // We combine immer and lodash to generate a new state object, so React can re-render the panel.
+ // Since our data node contains label and visibility properties, this combination can automatically handle label editing and node visibility toggling,
+ // without needing to write special handling logic.
+ setState(produce((draft) => set(draft, path, value)));
+
+ // If the topic is changed, update our subscription.
+ if (path[1] === 'topic') {
+ context.subscribe([{ topic: value as string }]);
+ }
+ }
+ },
+ [context],
+);
+```
+
+Next, we use `context.updatePanelSettingsEditor` to register settings in our panel, and when the settings state changes, use `context.saveState` to save the state to the layout.
+
+```ts
+// Update the settings editor each time our state or available topic list changes.
+useEffect(() => {
+ // Save current state to layout
+ context.saveState(state);
+
+ const topicOptions = (topics ?? []).map((topic) => ({ value: topic.name, label: topic.name }));
+
+ // We set up the settings tree to mirror the shape of our panel state, so we can use paths from the settings tree to directly update our state.
+ context.updatePanelSettingsEditor({
+ actionHandler,
+ nodes: {
+ data: {
+ // Our label comes from the label in state, and will update to reflect changes in the state value.
+ label: state.data.label,
+ // Setting this to true allows users to edit this node's label.
+ renamable: true,
+ // A non-undefined value here allows users to toggle this node's visibility.
+ visible: state.data.visible,
+ icon: 'Cube',
+ fields: {
+ topic: {
+ label: 'Topic',
+ input: 'select',
+ options: topicOptions,
+ value: state.data.topic,
+ },
+ },
+ },
+ appearance: {
+ label: 'Appearance',
+ icon: 'Shapes',
+ fields: {
+ theme: {
+ label: 'Theme',
+ input: 'select',
+ value: state.appearance.theme,
+ options: ThemeOptions,
+ },
+ indentWidth: {
+ label: 'Indent Width',
+ input: 'select',
+ value: state.appearance.indentWidth,
+ options: [
+ { value: '2', label: '2' },
+ { value: '4', label: '4' },
+ { value: '8', label: '8' },
+ ],
+ },
+ displayDataTypes: {
+ label: 'Display DataTypes',
+ input: 'boolean',
+ value: state.appearance.displayDataTypes,
+ },
+ },
+ },
+ },
+ });
+}, [context, actionHandler, state, topics]);
+```
+
+Then we need to make two small changes:
+
+- Check if `renderState.currentFrame` is undefined, if it is undefined, keep the data from the previous frame, don't clear the message.
+- Listen to the topic set in settings during initialization
+
+```ts
+useLayoutEffect(() => {
+ context.onRender = (renderState, done) => {
+ ...
+
+ // If currentFrame is undefined, keep the data from the previous frame, don't clear the message.
+ if (renderState.currentFrame) {
+ setMessages(renderState.currentFrame);
+ }
+ };
+
+ // After adding the render handler, you must specify which fields in the render state (RenderState) will trigger updates.
+ // If you don't monitor any fields, the panel context will think you don't need any updates, so the panel won't render.
+
+ // Tell the panel context we care about changes in the _topic_ field in RenderState
+ context.watch("topics");
+
+ // Tell the panel context we want to subscribe to messages in the current frame
+ context.watch("currentFrame");
+
+ // Subscribe to our initial topic
+ if (state.data.topic) {
+ context.subscribe([{ topic: state.data.topic }]);
+ }
+}, [context, state.data.topic]);
+```
+
+Finally, just use `@microlink/react-json-view` to draw the corresponding messages in the `return`.
+
+```ts
+return (
+
+
{state.data.topic ?? "Choose a topic in settings"}
+
+
+
+
+);
+```
+
+> You can find the complete code [here](https://github.com/coscene-io/create-coscene-extension/tree/main/examples/panel-settings)
+
+## Test Plugin
+
+To build and install the plugin for local testing in coStudio, run the following command in the plugin directory:
+
+```bash
+npm run local-install
+```
+
+In coStudio, open the plugin list on the right side, and you'll now see `custom raw message panel` in the list of installed plugins:
+
+
+The panel list will also have a new `custom-raw-message-panel` panel. Add our panel and open any file, and you can use our custom `custom-raw-message-panel` panel:
+
+
+You can choose the topic you want to view in the settings and customize the panel's appearance to view messages for the corresponding topic in the panel:
+
+
+## Share Your Plugin
+
+To share your plugin with others, you need to package it as a .coe file. To do this, run the following command in the plugin directory:
+
+```bash
+npm run package
+```
+
+You'll find an `unknown.custom-raw-message-panel-0.0.0.coe` file in the plugin directory. You can distribute this to others, and they can install it in their coStudio instance by dragging and dropping it.
diff --git a/i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/3-best-practices/_category_.json b/i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/3-best-practices/_category_.json
new file mode 100644
index 000000000..7c603b002
--- /dev/null
+++ b/i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/3-best-practices/_category_.json
@@ -0,0 +1,9 @@
+{
+ "label": "Best Practices",
+ "position": 3,
+ "collapsible": true,
+ "link": {
+ "type": "generated-index",
+ "slug": "/category/extensions/best-practices"
+ }
+}
\ No newline at end of file
diff --git a/i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/3-best-practices/img/3dPanel.png b/i18n/en/docusaurus-plugin-content-docs/current/viz/8-extensions/3-best-practices/img/3dPanel.png
new file mode 100644
index 0000000000000000000000000000000000000000..e4e02b66366f5118585663013ea22374d6d4df24
GIT binary patch
literal 338097
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