|
| 1 | +--- |
| 2 | +sidebar_position: 3 |
| 3 | +sidebar_label: Plugins SDK |
| 4 | +sidebar_class_name: hidden |
| 5 | +--- |
| 6 | + |
| 7 | +# Plugins SDK for HTML Reporter |
| 8 | + |
| 9 | +Reference for available dependencies, SDK components, and extension points for plugin development. |
| 10 | + |
| 11 | +## Available Dependencies |
| 12 | + |
| 13 | +Plugins can use the following dependencies provided by HTML Reporter at runtime. These dependencies do not need to be included in the bundle — they will be passed through the wrapper function. |
| 14 | + |
| 15 | +| Dependency | Description | |
| 16 | +| ------------------------------ | ---------------------------------------- | |
| 17 | +| `@gravity-ui/icons` | [Gravity UI Icons][gravity-ui-icons] | |
| 18 | +| `@gravity-ui/uikit` | [Gravity UI][gravity-ui] components | |
| 19 | +| `axios` | HTTP client for server requests | |
| 20 | +| `classnames` | Utility for working with CSS classes | |
| 21 | +| `html-reporter/plugins-sdk` | SDK for server part (ExtensionPointName) | |
| 22 | +| `html-reporter/plugins-sdk/ui` | SDK for UI components | |
| 23 | +| `immer` | Immutable state updates | |
| 24 | +| `lodash` | Data manipulation utilities | |
| 25 | +| `react` | React 18 | |
| 26 | +| `react-dom` | React DOM | |
| 27 | +| `react-redux` | React bindings for Redux | |
| 28 | +| `react/jsx-runtime` | JSX Runtime | |
| 29 | +| `redux` | Redux for state management | |
| 30 | +| `redux-thunk` | Middleware for async actions (built-in) | |
| 31 | +| `reselect` | Memoized selectors for Redux | |
| 32 | + |
| 33 | +## Plugins SDK UI {#plugins-sdk-ui} |
| 34 | + |
| 35 | +The `html-reporter/plugins-sdk/ui` module exports components and types for creating plugin UIs. |
| 36 | + |
| 37 | +### CollapsibleSection |
| 38 | + |
| 39 | +A collapsible section integrated with the report's Redux state. |
| 40 | + |
| 41 | +```typescript |
| 42 | +import { CollapsibleSection } from "html-reporter/plugins-sdk/ui"; |
| 43 | + |
| 44 | +interface CollapsibleSectionProps { |
| 45 | + /** Unique section identifier */ |
| 46 | + id: string; |
| 47 | + /** Section title */ |
| 48 | + title: string; |
| 49 | + /** Section content */ |
| 50 | + children?: ReactNode; |
| 51 | + /** CSS class */ |
| 52 | + className?: string; |
| 53 | + /** Whether the section is expanded by default */ |
| 54 | + defaultExpanded?: boolean; |
| 55 | + /** Callback when state changes */ |
| 56 | + onUpdate?: (expanded: boolean) => void; |
| 57 | +} |
| 58 | +``` |
| 59 | + |
| 60 | +Usage example: |
| 61 | + |
| 62 | +```tsx |
| 63 | +<CollapsibleSection |
| 64 | + id="plugins.my-plugin.section" |
| 65 | + title="My Section" |
| 66 | + defaultExpanded={false} |
| 67 | + onUpdate={expanded => { |
| 68 | + if (expanded) { |
| 69 | + // Load data when expanded |
| 70 | + } |
| 71 | + }} |
| 72 | +> |
| 73 | + <div>Section content</div> |
| 74 | +</CollapsibleSection> |
| 75 | +``` |
| 76 | + |
| 77 | +### PanelSection |
| 78 | + |
| 79 | +Section for the settings panel. |
| 80 | + |
| 81 | +```typescript |
| 82 | +import { PanelSection } from "html-reporter/plugins-sdk/ui"; |
| 83 | + |
| 84 | +interface PanelSectionProps { |
| 85 | + /** Section title */ |
| 86 | + title: ReactNode; |
| 87 | + /** Description */ |
| 88 | + description?: ReactNode; |
| 89 | + /** Content */ |
| 90 | + children?: ReactNode; |
| 91 | +} |
| 92 | +``` |
| 93 | + |
| 94 | +### State |
| 95 | + |
| 96 | +Type of the root Redux store state. |
| 97 | + |
| 98 | +```typescript |
| 99 | +import { State } from "html-reporter/plugins-sdk/ui"; |
| 100 | + |
| 101 | +// Use for typing selectors |
| 102 | +const mySelector = (state: State) => state.tree.results.byId; |
| 103 | +``` |
| 104 | + |
| 105 | +### Features |
| 106 | + |
| 107 | +Flags for available report features. |
| 108 | + |
| 109 | +```typescript |
| 110 | +import { Features } from "html-reporter/plugins-sdk/ui"; |
| 111 | + |
| 112 | +const availableFeatures = useSelector(state => { |
| 113 | + return state.app.availableFeatures; |
| 114 | +}); |
| 115 | +if (!availableFeatures.some(feature => feature.name === Features.RunTestsFeature.name)) { |
| 116 | + return null; |
| 117 | +} |
| 118 | +``` |
| 119 | + |
| 120 | +## The pluginOptions Object {#plugin-options} |
| 121 | + |
| 122 | +A global `pluginOptions` object is available in the plugin UI component: |
| 123 | + |
| 124 | +```typescript |
| 125 | +declare const pluginOptions: { |
| 126 | + /** Plugin name (from configuration) */ |
| 127 | + pluginName: string; |
| 128 | + /** Plugin configuration (config field from configuration) */ |
| 129 | + pluginConfig: object; |
| 130 | + /** Prefix for server endpoints: /plugin-routes/{pluginName}/ */ |
| 131 | + pluginServerEndpointPrefix: string; |
| 132 | + /** Report Redux actions */ |
| 133 | + actions: object; |
| 134 | + /** Report action names */ |
| 135 | + actionNames: object; |
| 136 | + /** Redux Store selectors, see html-reporter/lib/static/modules/selectors */ |
| 137 | + selectors: object; |
| 138 | +}; |
| 139 | +``` |
| 140 | + |
| 141 | +## Extension Points {#extension-points} |
| 142 | + |
| 143 | +Extension points determine where in the report interface the plugin component will be placed. |
| 144 | + |
| 145 | +| Point | Description | Component Props | |
| 146 | +| ------------------ | ------------------------------------------ | ---------------------------- | |
| 147 | +| `result_meta` | Test result area, near meta information | `result: ReporterTestResult` | |
| 148 | +| `settings-panel` | Settings panel | — | |
| 149 | +| `run-test-options` | Test run options, near the run test button | — | |
| 150 | + |
| 151 | +### ExtensionPointName |
| 152 | + |
| 153 | +Use enum to specify the extension point in the preset: |
| 154 | + |
| 155 | +```typescript |
| 156 | +import { ExtensionPointName } from "html-reporter/plugins-sdk"; |
| 157 | + |
| 158 | +// Available values: |
| 159 | +ExtensionPointName.ResultMeta; // "result_meta" |
| 160 | +ExtensionPointName.MenuBar; // "menu-bar" |
| 161 | +ExtensionPointName.Root; // "root" |
| 162 | +``` |
| 163 | + |
| 164 | +### Positioning |
| 165 | + |
| 166 | +The `position` parameter determines the component placement relative to the extension point: |
| 167 | + |
| 168 | +| Value | Description | |
| 169 | +| ---------- | ---------------------------------- | |
| 170 | +| `"before"` | Before the extension point content | |
| 171 | +| `"after"` | After the extension point content | |
| 172 | +| `"wrap"` | Wrap the extension point content | |
| 173 | + |
| 174 | +## CSS and Styling {#css-styling} |
| 175 | + |
| 176 | +### CSS Modules |
| 177 | + |
| 178 | +It is recommended to use CSS Modules for style isolation: |
| 179 | + |
| 180 | +```css title="Plugin.module.css" |
| 181 | +.container { |
| 182 | + padding: 16px; |
| 183 | +} |
| 184 | + |
| 185 | +.result { |
| 186 | + display: flex; |
| 187 | + gap: 8px; |
| 188 | +} |
| 189 | +``` |
| 190 | + |
| 191 | +```tsx |
| 192 | +import styles from "./Plugin.module.css"; |
| 193 | + |
| 194 | +<div className={styles.container}> |
| 195 | + <div className={styles.result}>...</div> |
| 196 | +</div>; |
| 197 | +``` |
| 198 | + |
| 199 | +### Gravity UI CSS Variables |
| 200 | + |
| 201 | +HTML Reporter uses the [Gravity UI theme][gravity-ui-theme]. You can use CSS variables for style consistency: |
| 202 | + |
| 203 | +```css |
| 204 | +.myElement { |
| 205 | + /* Text colors */ |
| 206 | + color: var(--g-color-text-primary); |
| 207 | + color: var(--g-color-text-secondary); |
| 208 | + color: var(--g-color-text-brand); |
| 209 | + color: var(--g-color-text-danger); |
| 210 | + |
| 211 | + /* Background colors */ |
| 212 | + background: var(--g-color-base-background); |
| 213 | + background: var(--g-color-base-brand); |
| 214 | + |
| 215 | + /* Borders */ |
| 216 | + border-color: var(--g-color-line-generic); |
| 217 | + |
| 218 | + /* Spacing and sizes */ |
| 219 | + padding: var(--g-spacing-2); /* 8px */ |
| 220 | + padding: var(--g-spacing-4); /* 16px */ |
| 221 | +} |
| 222 | +``` |
| 223 | + |
| 224 | +### CSS Injection into Bundle |
| 225 | + |
| 226 | +Use the `vite-plugin-css-injected-by-js` plugin to include CSS in the JavaScript bundle: |
| 227 | + |
| 228 | +```typescript title="vite.config.ts" |
| 229 | +import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js"; |
| 230 | + |
| 231 | +export default defineConfig({ |
| 232 | + plugins: [cssInjectedByJsPlugin()], |
| 233 | +}); |
| 234 | +``` |
| 235 | + |
| 236 | +## Typing {#typing} |
| 237 | + |
| 238 | +### Extending DefaultRootState |
| 239 | + |
| 240 | +To type the plugin state in Redux, extend `DefaultRootState`: |
| 241 | + |
| 242 | +```typescript title="types.d.ts" |
| 243 | +import type { State } from "html-reporter/plugins-sdk/ui"; |
| 244 | + |
| 245 | +interface MyPluginState { |
| 246 | + data: Record<string, { status: string; value: any }>; |
| 247 | +} |
| 248 | + |
| 249 | +declare module "react-redux" { |
| 250 | + export interface DefaultRootState extends State { |
| 251 | + plugins: { |
| 252 | + myPlugin: MyPluginState; |
| 253 | + }; |
| 254 | + } |
| 255 | +} |
| 256 | +``` |
| 257 | + |
| 258 | +### Global pluginOptions |
| 259 | + |
| 260 | +```typescript title="types.d.ts" |
| 261 | +declare global { |
| 262 | + const pluginOptions: { |
| 263 | + pluginConfig: MyPluginConfig; |
| 264 | + pluginServerEndpointPrefix: string; |
| 265 | + }; |
| 266 | +} |
| 267 | +``` |
| 268 | + |
| 269 | +[gravity-ui]: https://gravity-ui.com/ |
| 270 | +[gravity-ui-icons]: https://gravity-ui.com/icons |
| 271 | +[gravity-ui-theme]: https://gravity-ui.com/design/themes |
0 commit comments