diff --git a/Makefile b/Makefile
index 218fd972a51..a486bde8271 100644
--- a/Makefile
+++ b/Makefile
@@ -124,6 +124,9 @@ config-rebuild: ## Rebuild all sample YAML, RST files, and type stubs from confi
config-lint: ## lint galaxy YAML configuration file
$(CONFIG_MANAGE) lint galaxy
+client-gen-markdown-directives: ## Regenerate the Galaxy Markdown directive reference from directives.yml
+ $(IN_VENV) python scripts/markdown_directives_doc.py
+
release-ensure-upstream: ## Ensure upstream branch for release commands setup
ifeq (shell git remote -v | grep $(RELEASE_UPSTREAM), )
git remote add $(RELEASE_UPSTREAM) git@github.com:galaxyproject/galaxy.git
diff --git a/client/.prettierignore b/client/.prettierignore
index 70ab8556d27..251a71a7d39 100644
--- a/client/.prettierignore
+++ b/client/.prettierignore
@@ -13,3 +13,5 @@ src/libs
*.json
*.yml
*.yaml
+# Generated from directives.yml by scripts/markdown_directives_doc.py
+src/components/Markdown/directives.md
diff --git a/client/src/components/Markdown/directives.md b/client/src/components/Markdown/directives.md
new file mode 100644
index 00000000000..39a7eb5899b
--- /dev/null
+++ b/client/src/components/Markdown/directives.md
@@ -0,0 +1,415 @@
+# Galaxy Markdown Directive Reference
+
+Generated from `directives.yml` by `scripts/markdown_directives_doc.py` (`make client-gen-markdown-directives`). Do not edit by hand.
+
+## Syntax
+
+**Block** — works for every directive; required in workflow report templates:
+
+````
+```galaxy
+directive_name(arg=value)
+```
+````
+
+One directive per fenced `galaxy` block. **Inline** (`${galaxy ...}`) works only for the [embeddable directives](#embeddable-directives).
+
+## Argument value types
+
+| Type | Meaning |
+|---|---|
+| `label` | Workflow input/output/step label; resolved to an ID per invocation. |
+| `id` | Encoded (export) or numeric (internal) object ID. |
+| `int` | Integer. |
+| `boolean` | `true` or `false`. |
+| `enum` | One of a fixed set of values. |
+| `string` | Free display text. |
+| `path` | File within a composite / extra-files dataset. |
+
+## Addressing contexts
+
+The same directive accepts different parameters depending on how the object is referenced:
+
+| Context | Use |
+|---|---|
+| `report` | Workflow report template — labels resolve per invocation. |
+| `page` | Page / direct contexts — encoded or numeric IDs. |
+| `notebook` | History-relative reference (notebooks). |
+| `invocation` | Invocation reference — usually injected automatically. |
+
+## Universal argument
+
+`collapse=""` — wraps a block directive in a collapsible section. Valid on every directive.
+
+---
+
+## Dataset directives
+
+| Directive | Embed | Requires | Renders |
+|---|---|---|---|
+| `history_dataset_display` | | `history_dataset_id` | Interactive dataset card with view/import/download options. |
+| `history_dataset_as_image` | ✅ | `history_dataset_id` | Dataset embedded as an image. |
+| `history_dataset_index` | | `history_dataset_id` | File/folder listing of a composite dataset. |
+| `history_dataset_embedded` | | `history_dataset_id` | Raw dataset content inline. |
+| `history_dataset_as_table` | | `history_dataset_id` | Tabular dataset as a formatted table. |
+| `history_dataset_type` | ✅ | `history_dataset_id` | Datatype string as text. |
+| `history_dataset_link` | | `history_dataset_id` | Download link for a dataset. |
+| `history_dataset_name` | ✅ | `history_dataset_id` | Dataset name as text. |
+| `history_dataset_peek` | | `history_dataset_id` | Dataset "peek" preview. |
+| `history_dataset_info` | | `history_dataset_id` | Dataset "info" metadata. |
+
+### `history_dataset_display`
+
+Display a dataset and relevant options for viewing, importing, downloading,
+and visualization in the resulting document. To embed a dataset directly
+into the document use the "history_dataset_embedded" / "Embedded Dataset"
+directive.
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `output` | `label` | `report` | | Workflow output label, resolved per invocation (report templates). |
+| `input` | `label` | `report` | | Workflow input label, resolved per invocation (report templates). |
+| `hid` | `int` | `notebook` | | History item hid. |
+| `history_dataset_id` | `id` | `page` | | Encoded (export) or numeric (internal) dataset ID. |
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+
+### `history_dataset_as_image`
+
+Embed a dataset in the resulting document as an image. This only works for simple image
+types. This can be used to present graphs and other visual summaries of an analysis into
+a Galaxy Markdown document summary.
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `output` | `label` | `report` | | Workflow output label, resolved per invocation (report templates). |
+| `input` | `label` | `report` | | Workflow input label, resolved per invocation (report templates). |
+| `hid` | `int` | `notebook` | | History item hid. |
+| `history_dataset_id` | `id` | `page` | | Encoded (export) or numeric (internal) dataset ID. |
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+| `path` | `path` | | | File within a composite / extra-files dataset. |
+
+### `history_dataset_index`
+
+For Galaxy composite datasets (datasets that consist on multiple files), this option will
+display the contents of the composite dataset as files and folders in the resulting document.
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `output` | `label` | `report` | | Workflow output label, resolved per invocation (report templates). |
+| `input` | `label` | `report` | | Workflow input label, resolved per invocation (report templates). |
+| `hid` | `int` | `notebook` | | History item hid. |
+| `history_dataset_id` | `id` | `page` | | Encoded (export) or numeric (internal) dataset ID. |
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+| `path` | `path` | | | File within a composite / extra-files dataset. |
+
+### `history_dataset_embedded`
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `output` | `label` | `report` | | Workflow output label, resolved per invocation (report templates). |
+| `input` | `label` | `report` | | Workflow input label, resolved per invocation (report templates). |
+| `hid` | `int` | `notebook` | | History item hid. |
+| `history_dataset_id` | `id` | `page` | | Encoded (export) or numeric (internal) dataset ID. |
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+
+### `history_dataset_as_table`
+
+Embed a dataset in the resulting document as a table. This only works for datasets with tabular
+datatypes. This command works a lot like "history_dataset_embedded" but provides specialized options
+for controlling the way tabular data is displayed in the resulting document.
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `output` | `label` | `report` | | Workflow output label, resolved per invocation (report templates). |
+| `input` | `label` | `report` | | Workflow input label, resolved per invocation (report templates). |
+| `hid` | `int` | `notebook` | | History item hid. |
+| `history_dataset_id` | `id` | `page` | | Encoded (export) or numeric (internal) dataset ID. |
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+| `title` | `string` | | | Table title. |
+| `footer` | `string` | | | Table footer. |
+| `compact` | `boolean` | | `false` | Compact row height. |
+| `show_column_headers` | `boolean` | | `true` | Show column headers. |
+| `path` | `path` | | | File within a composite / extra-files dataset. |
+
+### `history_dataset_type`
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `output` | `label` | `report` | | Workflow output label, resolved per invocation (report templates). |
+| `input` | `label` | `report` | | Workflow input label, resolved per invocation (report templates). |
+| `hid` | `int` | `notebook` | | History item hid. |
+| `history_dataset_id` | `id` | `page` | | Encoded (export) or numeric (internal) dataset ID. |
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+
+### `history_dataset_link`
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `output` | `label` | `report` | | Workflow output label, resolved per invocation (report templates). |
+| `input` | `label` | `report` | | Workflow input label, resolved per invocation (report templates). |
+| `hid` | `int` | `notebook` | | History item hid. |
+| `history_dataset_id` | `id` | `page` | | Encoded (export) or numeric (internal) dataset ID. |
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+| `label` | `string` | | | Link text. |
+| `path` | `path` | | | File within a composite / extra-files dataset. |
+
+### `history_dataset_name`
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `output` | `label` | `report` | | Workflow output label, resolved per invocation (report templates). |
+| `input` | `label` | `report` | | Workflow input label, resolved per invocation (report templates). |
+| `hid` | `int` | `notebook` | | History item hid. |
+| `history_dataset_id` | `id` | `page` | | Encoded (export) or numeric (internal) dataset ID. |
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+
+### `history_dataset_peek`
+
+Display a dataset metadata's "peek" field in the resulting document - this is datatype dependent
+metadata but usually this is a few lines from the start of a file.
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `output` | `label` | `report` | | Workflow output label, resolved per invocation (report templates). |
+| `input` | `label` | `report` | | Workflow input label, resolved per invocation (report templates). |
+| `hid` | `int` | `notebook` | | History item hid. |
+| `history_dataset_id` | `id` | `page` | | Encoded (export) or numeric (internal) dataset ID. |
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+
+### `history_dataset_info`
+
+Display a dataset metadata's "info" field in the resulting document. This info field is
+usually based on the output of the tool run and sometimes contains useful metadata about a
+dataset.
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `output` | `label` | `report` | | Workflow output label, resolved per invocation (report templates). |
+| `input` | `label` | `report` | | Workflow input label, resolved per invocation (report templates). |
+| `hid` | `int` | `notebook` | | History item hid. |
+| `history_dataset_id` | `id` | `page` | | Encoded (export) or numeric (internal) dataset ID. |
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+
+---
+
+## Collection directives
+
+| Directive | Embed | Requires | Renders |
+|---|---|---|---|
+| `history_dataset_collection_display` | | `history_dataset_collection_id` | Collection browser for paired/list collections. |
+
+### `history_dataset_collection_display`
+
+Display a dataset collection and relevant options for viewing, importing, downloading
+in the resulting document.
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `output` | `label` | `report` | | Workflow output label, resolved per invocation (report templates). |
+| `input` | `label` | `report` | | Workflow input label, resolved per invocation (report templates). |
+| `hid` | `int` | `notebook` | | History item hid. |
+| `history_dataset_collection_id` | `id` | `page` | | Encoded or numeric dataset collection ID. |
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+
+---
+
+## Invocation directives
+
+| Directive | Embed | Requires | Renders |
+|---|---|---|---|
+| `history_link` | | `history_id` | Link to import the referenced history. |
+| `invocation_inputs` | | `invocation_id` | Summary of all workflow inputs. |
+| `invocation_outputs` | | `invocation_id` | Summary of all workflow outputs. |
+| `invocation_time` | ✅ | `invocation_id` | Invocation run timestamp. |
+
+### `history_link`
+
+Add a link to import the history the workflow invocation was executed in.
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `history_id` | `id` | `page` | | Encoded or numeric history ID. |
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+
+### `invocation_inputs`
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+
+### `invocation_outputs`
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+
+### `invocation_time`
+
+Display this workflow run's invocation time in the resulting document.
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+
+---
+
+## Workflow directives
+
+| Directive | Embed | Requires | Renders |
+|---|---|---|---|
+| `workflow_display` | | `workflow_id` | Step-by-step text description of a workflow. |
+| `workflow_image` | | `workflow_id` | SVG workflow diagram. |
+| `workflow_license` | ✅ | `workflow_id` | Workflow license information. |
+
+### `workflow_display`
+
+Embed a text description of this workflow's steps in the resulting document.
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `workflow_id` | `id` | `page` | | Stored workflow ID. |
+| `workflow_checkpoint` | `int` | `page` | | Workflow version index. |
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+
+### `workflow_image`
+
+Embed a rough image this workflow in the resulting document.
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `workflow_id` | `id` | `page` | | Stored workflow ID. |
+| `workflow_checkpoint` | `int` | `page` | | Workflow version index. |
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+| `size` | enum (`sm`, `md`, `lg`) | | `lg` | Image width (sm=300px, md=550px, lg=100%). |
+
+### `workflow_license`
+
+Display this workflow's license in the resulting document.
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `workflow_id` | `id` | `page` | | Stored workflow ID. |
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+
+---
+
+## Job directives
+
+| Directive | Embed | Requires | Renders |
+|---|---|---|---|
+| `job_metrics` | | `job_id` | Runtime metrics table for a job. |
+| `job_parameters` | | `job_id` | Tool parameters table for a job. |
+| `tool_stdout` | | `job_id` | Tool standard output for a job. |
+| `tool_stderr` | | `job_id` | Tool standard error for a job. |
+
+### `job_metrics`
+
+Embed the job metrics for this job in the resulting document (if Galaxy is configured and you have
+permission).
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `step` | `label` | `report` | | Workflow step label, resolved per invocation (report templates). |
+| `job_id` | `id` | `page` | | Encoded or numeric job ID. |
+| `implicit_collection_jobs_id` | `id` | `page` | | Mapped-collection job group ID. |
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+
+### `job_parameters`
+
+Embed the tool parameters for a job in the resulting document.
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `step` | `label` | `report` | | Workflow step label, resolved per invocation (report templates). |
+| `job_id` | `id` | `page` | | Encoded or numeric job ID. |
+| `implicit_collection_jobs_id` | `id` | `page` | | Mapped-collection job group ID. |
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+| `footer` | `string` | | | Table footer. |
+
+### `tool_stdout`
+
+Embed the tool standard output stream for a job in the resulting document.
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `step` | `label` | `report` | | Workflow step label, resolved per invocation (report templates). |
+| `job_id` | `id` | `page` | | Encoded or numeric job ID. |
+| `implicit_collection_jobs_id` | `id` | `page` | | Mapped-collection job group ID. |
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+
+### `tool_stderr`
+
+Embed the tool standard error stream for a job in the resulting document.
+
+| Parameter | Type | Context | Default | Description |
+|---|---|---|---|---|
+| `step` | `label` | `report` | | Workflow step label, resolved per invocation (report templates). |
+| `job_id` | `id` | `page` | | Encoded or numeric job ID. |
+| `implicit_collection_jobs_id` | `id` | `page` | | Mapped-collection job group ID. |
+| `invocation_id` | `id` | `invocation` | | Invocation ID; usually injected automatically during resolution. |
+
+---
+
+## Visualization directive
+
+| Directive | Embed | Requires | Renders |
+|---|---|---|---|
+| `visualization` | | `history_dataset_id` | Galaxy plugin-based visualization. |
+
+### `visualization`
+
+Embed a Galaxy visualization in the resulting document. Accepts arguments specific to the
+selected visualization plugin; these arguments are not validated by the Galaxy Markdown parser.
+
+---
+
+## Utility & instance directives
+
+| Directive | Embed | Requires | Renders |
+|---|---|---|---|
+| `generate_time` | ✅ | — | Current time at generation. |
+| `generate_galaxy_version` | ✅ | — | Galaxy version string at generation. |
+| `instance_access_link` | ✅ | — | Link to the Galaxy instance. |
+| `instance_resources_link` | ✅ | — | Link to instance resources. |
+| `instance_help_link` | ✅ | — | Link to instance help. |
+| `instance_support_link` | ✅ | — | Link to instance support. |
+| `instance_citation_link` | ✅ | — | Link to instance citation information. |
+| `instance_terms_link` | ✅ | — | Link to instance terms. |
+| `instance_organization_link` | ✅ | — | Link to the instance's organization. |
+
+### `generate_time`
+
+Report the current time of report generation.
+
+Warning: This is the time the report was generated and not the time of
+an analysis. This option makes the most sense for PDF generation of reports
+designed for external archiving or printing.
+
+### `generate_galaxy_version`
+
+Report the current Galaxy version at the time report generation.
+
+Warning: This is the Galaxy version at the time the report was generated and
+not the time of an analysis. This option makes the most sense for PDF generation
+of reports designed for external archiving or printing.
+
+---
+
+## Embeddable directives
+
+Inline `${galaxy ...}` syntax is supported only for these directives; all others require block syntax.
+
+- `history_dataset_as_image`
+- `history_dataset_name`
+- `history_dataset_type`
+- `workflow_license`
+- `invocation_time`
+- `generate_time`
+- `generate_galaxy_version`
+- `instance_access_link`
+- `instance_resources_link`
+- `instance_help_link`
+- `instance_support_link`
+- `instance_citation_link`
+- `instance_terms_link`
+- `instance_organization_link`
diff --git a/client/src/components/Markdown/directives.ts b/client/src/components/Markdown/directives.ts
index 22901a0285c..525bb475bf5 100644
--- a/client/src/components/Markdown/directives.ts
+++ b/client/src/components/Markdown/directives.ts
@@ -6,10 +6,25 @@ type DirectiveMetadataValueByMode = {
[key: string]: string;
};
+interface DirectiveParameter {
+ type: string;
+ context?: string;
+ description?: string;
+ default?: string | boolean;
+ values?: string[];
+}
+
interface DirectiveMetadata {
side_panel_name: string | DirectiveMetadataValueByMode;
side_panel_description?: string | DirectiveMetadataValueByMode;
help?: string | DirectiveMetadataValueByMode;
+ category?: string;
+ renders?: string;
+ embeddable?: boolean;
+ requires?: string;
+ parameter_set?: string;
+ parameters?: { [key: string]: DirectiveParameter };
+ dynamic_parameters?: boolean;
}
type DirectivesMetadata = {
diff --git a/client/src/components/Markdown/directives.yml b/client/src/components/Markdown/directives.yml
index 480942adca6..0e0a2ab1da4 100644
--- a/client/src/components/Markdown/directives.yml
+++ b/client/src/components/Markdown/directives.yml
@@ -1,5 +1,110 @@
---
+# Metadata describing every Galaxy Markdown directive.
+#
+# Consumed at runtime by directives.ts (editor side panel) and used to generate the
+# human-readable reference directives.md via scripts/markdown_directives_doc.py.
+# The parameter, embeddable and requirement metadata here is checked against the
+# authoritative validator in lib/galaxy/managers/markdown_parse.py (and
+# Utilities/requirements.yml) by test/unit/app/test_markdown_directives_doc.py, so
+# keep them in sync.
+#
+# Keys starting with "_" are shared schema fragments, not directives.
+#
+# Per-directive fields:
+# category grouping used in the generated reference
+# renders one-line summary of the rendered output
+# embeddable true when usable inline via ${galaxy ...} (EMBED_CAPABLE_DIRECTIVES)
+# requires primary object the directive needs (mirrors requirements.yml)
+# parameter_set name of a shared bundle under _parameter_sets to include
+# parameters directive-specific arguments (name -> type/default/context/description)
+# dynamic_parameters true when arbitrary arguments are accepted (not validated)
+# The shared "collapse" argument is valid on every directive and is documented globally.
+
+_parameter_sets:
+ dataset_addressing:
+ output:
+ type: label
+ context: report
+ description: Workflow output label, resolved per invocation (report templates).
+ input:
+ type: label
+ context: report
+ description: Workflow input label, resolved per invocation (report templates).
+ hid:
+ type: int
+ context: notebook
+ description: History item hid.
+ history_dataset_id:
+ type: id
+ context: page
+ description: Encoded (export) or numeric (internal) dataset ID.
+ invocation_id:
+ type: id
+ context: invocation
+ description: Invocation ID; usually injected automatically during resolution.
+ collection_addressing:
+ output:
+ type: label
+ context: report
+ description: Workflow output label, resolved per invocation (report templates).
+ input:
+ type: label
+ context: report
+ description: Workflow input label, resolved per invocation (report templates).
+ hid:
+ type: int
+ context: notebook
+ description: History item hid.
+ history_dataset_collection_id:
+ type: id
+ context: page
+ description: Encoded or numeric dataset collection ID.
+ invocation_id:
+ type: id
+ context: invocation
+ description: Invocation ID; usually injected automatically during resolution.
+ job_addressing:
+ step:
+ type: label
+ context: report
+ description: Workflow step label, resolved per invocation (report templates).
+ job_id:
+ type: id
+ context: page
+ description: Encoded or numeric job ID.
+ implicit_collection_jobs_id:
+ type: id
+ context: page
+ description: Mapped-collection job group ID.
+ invocation_id:
+ type: id
+ context: invocation
+ description: Invocation ID; usually injected automatically during resolution.
+ workflow_addressing:
+ workflow_id:
+ type: id
+ context: page
+ description: Stored workflow ID.
+ workflow_checkpoint:
+ type: int
+ context: page
+ description: Workflow version index.
+ invocation_id:
+ type: id
+ context: invocation
+ description: Invocation ID; usually injected automatically during resolution.
+ invocation_addressing:
+ invocation_id:
+ type: id
+ context: invocation
+ description: Invocation ID; usually injected automatically during resolution.
+
history_dataset_display:
+ category: dataset
+ renders: Interactive dataset card with view/import/download options.
+ embeddable: false
+ requires: history_dataset_id
+ parameter_set: dataset_addressing
side_panel_name: Dataset
help: |
Display a dataset and relevant options for viewing, importing, downloading,
@@ -8,12 +113,26 @@ history_dataset_display:
directive.
history_dataset_collection_display:
+ category: collection
+ renders: Collection browser for paired/list collections.
+ embeddable: false
+ requires: history_dataset_collection_id
+ parameter_set: collection_addressing
side_panel_name: Collection
help: |
Display a dataset collection and relevant options for viewing, importing, downloading
- in the resulting documenting.
+ in the resulting document.
history_dataset_as_image:
+ category: dataset
+ renders: Dataset embedded as an image.
+ embeddable: true
+ requires: history_dataset_id
+ parameter_set: dataset_addressing
+ parameters:
+ path:
+ type: path
+ description: File within a composite / extra-files dataset.
side_panel_name: Image
help: |
Embed a dataset in the resulting document as an image. This only works for simple image
@@ -21,31 +140,106 @@ history_dataset_as_image:
a Galaxy Markdown document summary.
history_dataset_index:
+ category: dataset
+ renders: File/folder listing of a composite dataset.
+ embeddable: false
+ requires: history_dataset_id
+ parameter_set: dataset_addressing
+ parameters:
+ path:
+ type: path
+ description: File within a composite / extra-files dataset.
side_panel_name: Dataset Index
help: |
For Galaxy composite datasets (datasets that consist on multiple files), this option will
display the contents of the composite dataset as files and folders in the resulting document.
+
history_dataset_embedded:
+ category: dataset
+ renders: Raw dataset content inline.
+ embeddable: false
+ requires: history_dataset_id
+ parameter_set: dataset_addressing
side_panel_name: Embedded Dataset
+
history_dataset_as_table:
+ category: dataset
+ renders: Tabular dataset as a formatted table.
+ embeddable: false
+ requires: history_dataset_id
+ parameter_set: dataset_addressing
+ parameters:
+ title:
+ type: string
+ description: Table title.
+ footer:
+ type: string
+ description: Table footer.
+ compact:
+ type: boolean
+ default: false
+ description: Compact row height.
+ show_column_headers:
+ type: boolean
+ default: true
+ description: Show column headers.
+ path:
+ type: path
+ description: File within a composite / extra-files dataset.
side_panel_name: Embedded Dataset as table
help: |
Embed a dataset in the resulting document as a table. This only works for datasets with tabular
datatypes. This command works a lot like "history_dataset_embedded" but provides specialized options
for controlling the way tabular data is displayed in the resulting document.
+
history_dataset_type:
+ category: dataset
+ renders: Datatype string as text.
+ embeddable: true
+ requires: history_dataset_id
+ parameter_set: dataset_addressing
side_panel_name: Dataset Type
+
history_dataset_link:
+ category: dataset
+ renders: Download link for a dataset.
+ embeddable: false
+ requires: history_dataset_id
+ parameter_set: dataset_addressing
+ parameters:
+ label:
+ type: string
+ description: Link text.
+ path:
+ type: path
+ description: File within a composite / extra-files dataset.
side_panel_name: Link to Dataset
+
history_dataset_name:
+ category: dataset
+ renders: Dataset name as text.
+ embeddable: true
+ requires: history_dataset_id
+ parameter_set: dataset_addressing
side_panel_name: Name of Dataset
+
history_dataset_peek:
+ category: dataset
+ renders: Dataset "peek" preview.
+ embeddable: false
+ requires: history_dataset_id
+ parameter_set: dataset_addressing
side_panel_name: Peek into Dataset
help: |
Display a dataset metadata's "peek" field in the resulting document - this is datatype dependent
metadata but usually this is a few lines from the start of a file.
history_dataset_info:
+ category: dataset
+ renders: Dataset "info" metadata.
+ embeddable: false
+ requires: history_dataset_id
+ parameter_set: dataset_addressing
side_panel_name: Dataset Details
help: |
Display a dataset metadata's "info" field in the resulting document. This info field is
@@ -53,6 +247,19 @@ history_dataset_info:
dataset.
history_link:
+ category: invocation
+ renders: Link to import the referenced history.
+ embeddable: false
+ requires: history_id
+ parameters:
+ history_id:
+ type: id
+ context: page
+ description: Encoded or numeric history ID.
+ invocation_id:
+ type: id
+ context: invocation
+ description: Invocation ID; usually injected automatically during resolution.
side_panel_name: Link to Import
help:
report: |
@@ -60,11 +267,31 @@ history_link:
page: |
Add a link to import the target history referenced by the directive.
+invocation_inputs:
+ category: invocation
+ renders: Summary of all workflow inputs.
+ embeddable: false
+ requires: invocation_id
+ parameter_set: invocation_addressing
+ side_panel_name: Invocation Inputs
+
+invocation_outputs:
+ category: invocation
+ renders: Summary of all workflow outputs.
+ embeddable: false
+ requires: invocation_id
+ parameter_set: invocation_addressing
+ side_panel_name: Invocation Output
+
invocation_time:
+ category: invocation
+ renders: Invocation run timestamp.
+ embeddable: true
+ requires: invocation_id
+ parameter_set: invocation_addressing
side_panel_name:
report: Time Workflow
page: Time a Workflow
-
side_panel_description: was invoked
help:
report: |
@@ -72,29 +299,12 @@ invocation_time:
page: |
Display a workflow run's invocation time in the resulting document.
-invocation_inputs:
- side_panel_name: Invocation Inputs
-
-invocation_outputs:
- side_panel_name: Invocation Output
-
-workflow_license:
- side_panel_name: Workflow License
- help:
- report: |
- Display this workflow's license in the resulting document.
- page: |
- Display a workflow's license in the resulting document.
-
-workflow_image:
- side_panel_name: Workflow (as image)
- help:
- report: |
- Embed a rough image this workflow in the resulting document.
- page: |
- Embed a rough image a workflow in the resulting document.
-
workflow_display:
+ category: workflow
+ renders: Step-by-step text description of a workflow.
+ embeddable: false
+ requires: workflow_id
+ parameter_set: workflow_addressing
side_panel_name:
report: Current Workflow
page: Display a Workflow
@@ -105,18 +315,111 @@ workflow_display:
page: |
Embed a text description of a workflow's steps in the resulting document.
-generate_galaxy_version:
- side_panel_name: Galaxy Version
- side_panel_description: as text
+workflow_image:
+ category: workflow
+ renders: SVG workflow diagram.
+ embeddable: false
+ requires: workflow_id
+ parameter_set: workflow_addressing
+ parameters:
+ size:
+ type: enum
+ values: [sm, md, lg]
+ default: lg
+ description: Image width (sm=300px, md=550px, lg=100%).
+ side_panel_name: Workflow (as image)
+ help:
+ report: |
+ Embed a rough image this workflow in the resulting document.
+ page: |
+ Embed a rough image a workflow in the resulting document.
+workflow_license:
+ category: workflow
+ renders: Workflow license information.
+ embeddable: true
+ requires: workflow_id
+ parameters:
+ workflow_id:
+ type: id
+ context: page
+ description: Stored workflow ID.
+ invocation_id:
+ type: id
+ context: invocation
+ description: Invocation ID; usually injected automatically during resolution.
+ side_panel_name: Workflow License
+ help:
+ report: |
+ Display this workflow's license in the resulting document.
+ page: |
+ Display a workflow's license in the resulting document.
+
+job_metrics:
+ category: job
+ renders: Runtime metrics table for a job.
+ embeddable: false
+ requires: job_id
+ parameter_set: job_addressing
+ side_panel_name: Job Metrics
+ side_panel_description: as table
help: |
- Report the current Galaxy version at the time %MODE% generation.
+ Embed the job metrics for this job in the resulting document (if Galaxy is configured and you have
+ permission).
- Warning: This is the Galaxy version at the time the %MODE% was generated and
- not the time of an analysis. This option makes the most sense for PDF generation
- of %MODE%s designed for external archiving or printing.
+job_parameters:
+ category: job
+ renders: Tool parameters table for a job.
+ embeddable: false
+ requires: job_id
+ parameter_set: job_addressing
+ parameters:
+ footer:
+ type: string
+ description: Table footer.
+ side_panel_name: Job Parameters
+ side_panel_description: as table
+ help: |
+ Embed the tool parameters for a job in the resulting document.
+
+tool_stdout:
+ category: job
+ renders: Tool standard output for a job.
+ embeddable: false
+ requires: job_id
+ parameter_set: job_addressing
+ side_panel_name: Tool Output
+ side_panel_description: of job run
+ help: |
+ Embed the tool standard output stream for a job in the resulting document.
+
+tool_stderr:
+ category: job
+ renders: Tool standard error for a job.
+ embeddable: false
+ requires: job_id
+ parameter_set: job_addressing
+ side_panel_name: Tool Error
+ side_panel_description: of job run
+ help: |
+ Embed the tool standard error stream for a job in the resulting document.
+
+visualization:
+ category: visualization
+ renders: Galaxy plugin-based visualization.
+ embeddable: false
+ requires: history_dataset_id
+ dynamic_parameters: true
+ side_panel_name: Visualization
+ help: |
+ Embed a Galaxy visualization in the resulting document. Accepts arguments specific to the
+ selected visualization plugin; these arguments are not validated by the Galaxy Markdown parser.
generate_time:
+ category: utility
+ renders: Current time at generation.
+ embeddable: true
+ requires: none
side_panel_name: Current Time
side_panel_description: as text
help: |
@@ -126,27 +429,65 @@ generate_time:
an analysis. This option makes the most sense for PDF generation of %MODE%s
designed for external archiving or printing.
-job_metrics:
- side_panel_name: Job Metrics
- side_panel_description: as table
+generate_galaxy_version:
+ category: utility
+ renders: Galaxy version string at generation.
+ embeddable: true
+ requires: none
+ side_panel_name: Galaxy Version
+ side_panel_description: as text
help: |
- Embed the job metrics for this job in the resulting document (if Galaxy is configured and you have
- permission).
+ Report the current Galaxy version at the time %MODE% generation.
-job_parameters:
- side_panel_name: Job Parameters
- side_panel_description: as table
- help: |
- Embed the tool parameters for a job in the resulting document.
+ Warning: This is the Galaxy version at the time the %MODE% was generated and
+ not the time of an analysis. This option makes the most sense for PDF generation
+ of %MODE%s designed for external archiving or printing.
-tool_stdout:
- side_panel_name: Tool Output
- side_panel_description: of job run
- help: |
- Embed the tool standard output stream for a job in the resulting document.
+instance_access_link:
+ category: utility
+ renders: Link to the Galaxy instance.
+ embeddable: true
+ requires: none
+ side_panel_name: Instance Access Link
-tool_stderr:
- side_panel_name: Tool Error
- side_panel_description: of job run
- help: |
- Embed the tool standard error stream for a job in the resulting document.
+instance_resources_link:
+ category: utility
+ renders: Link to instance resources.
+ embeddable: true
+ requires: none
+ side_panel_name: Instance Resources Link
+
+instance_help_link:
+ category: utility
+ renders: Link to instance help.
+ embeddable: true
+ requires: none
+ side_panel_name: Instance Help Link
+
+instance_support_link:
+ category: utility
+ renders: Link to instance support.
+ embeddable: true
+ requires: none
+ side_panel_name: Instance Support Link
+
+instance_citation_link:
+ category: utility
+ renders: Link to instance citation information.
+ embeddable: true
+ requires: none
+ side_panel_name: Instance Citation Link
+
+instance_terms_link:
+ category: utility
+ renders: Link to instance terms.
+ embeddable: true
+ requires: none
+ side_panel_name: Instance Terms Link
+
+instance_organization_link:
+ category: utility
+ renders: Link to the instance's organization.
+ embeddable: true
+ requires: none
+ side_panel_name: Instance Organization Link
diff --git a/scripts/markdown_directives_doc.py b/scripts/markdown_directives_doc.py
new file mode 100644
index 00000000000..56650d0e10c
--- /dev/null
+++ b/scripts/markdown_directives_doc.py
@@ -0,0 +1,320 @@
+#!/usr/bin/env python
+"""Generate the Galaxy Markdown directive reference from directives.yml.
+
+directives.yml is the source of truth for directive documentation metadata. This
+script renders it to a Markdown reference (directives.md) and can also verify that
+the metadata is consistent with the authoritative validator in
+``galaxy.managers.markdown_parse`` and that the checked-in reference is up to date.
+
+Usage::
+
+ python scripts/markdown_directives_doc.py # (re)write directives.md
+ python scripts/markdown_directives_doc.py --check # verify, non-zero exit on drift
+"""
+
+import argparse
+import os
+import sys
+
+sys.path.insert(1, os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, "lib")))
+
+import yaml
+
+from galaxy.managers.markdown_parse import (
+ DynamicArguments,
+ EMBED_CAPABLE_DIRECTIVES,
+ SHARED_ARGUMENTS,
+ VALID_ARGUMENTS,
+)
+
+MARKDOWN_DIR = os.path.abspath(
+ os.path.join(os.path.dirname(__file__), os.pardir, "client", "src", "components", "Markdown")
+)
+DIRECTIVES_YML = os.path.join(MARKDOWN_DIR, "directives.yml")
+REQUIREMENTS_YML = os.path.join(MARKDOWN_DIR, "Utilities", "requirements.yml")
+OUTPUT_MD = os.path.join(MARKDOWN_DIR, "directives.md")
+
+CATEGORY_ORDER = ["dataset", "collection", "invocation", "workflow", "job", "visualization", "utility"]
+CATEGORY_TITLES = {
+ "dataset": "Dataset directives",
+ "collection": "Collection directives",
+ "invocation": "Invocation directives",
+ "workflow": "Workflow directives",
+ "job": "Job directives",
+ "visualization": "Visualization directive",
+ "utility": "Utility & instance directives",
+}
+
+TYPE_ORDER = ["label", "id", "int", "boolean", "enum", "string", "path"]
+TYPE_NOTES = {
+ "label": "Workflow input/output/step label; resolved to an ID per invocation.",
+ "id": "Encoded (export) or numeric (internal) object ID.",
+ "int": "Integer.",
+ "boolean": "`true` or `false`.",
+ "enum": "One of a fixed set of values.",
+ "string": "Free display text.",
+ "path": "File within a composite / extra-files dataset.",
+}
+
+CONTEXT_ORDER = ["report", "page", "notebook", "invocation"]
+CONTEXT_NOTES = {
+ "report": "Workflow report template — labels resolve per invocation.",
+ "page": "Page / direct contexts — encoded or numeric IDs.",
+ "notebook": "History-relative reference (notebooks).",
+ "invocation": "Invocation reference — usually injected automatically.",
+}
+
+
+def load_directives(path=DIRECTIVES_YML):
+ """Return (parameter_sets, directives) parsed from directives.yml."""
+ with open(path) as f:
+ data = yaml.safe_load(f)
+ parameter_sets = data.get("_parameter_sets", {})
+ directives = {key: value for key, value in data.items() if not key.startswith("_")}
+ return parameter_sets, directives
+
+
+def load_requirements(path=REQUIREMENTS_YML):
+ """Return a mapping of directive -> required object from requirements.yml."""
+ with open(path) as f:
+ data = yaml.safe_load(f)
+ requires = {}
+ for obj, directives in data.items():
+ for directive in directives:
+ requires[directive] = obj
+ return requires
+
+
+def resolve_parameters(entry, parameter_sets):
+ """Merge a directive's shared parameter_set and inline parameters, preserving order."""
+ parameters = {}
+ set_name = entry.get("parameter_set")
+ if set_name and set_name in parameter_sets:
+ parameters.update(parameter_sets[set_name])
+ parameters.update(entry.get("parameters", {}))
+ return parameters
+
+
+def _mode_value(value):
+ """Collapse a possibly mode-keyed value to a single string (prefer report)."""
+ if isinstance(value, dict):
+ value = value.get("report") or value.get("page") or next(iter(value.values()))
+ return value
+
+
+def consistency_errors(parameter_sets, directives, requirements):
+ """Return a list of human-readable mismatches between directives.yml and the validator."""
+ errors = []
+
+ yml_names = set(directives)
+ valid_names = set(VALID_ARGUMENTS)
+ for missing in sorted(valid_names - yml_names):
+ errors.append(f"directives.yml is missing an entry for directive '{missing}'")
+ for extra in sorted(yml_names - valid_names):
+ errors.append(f"directives.yml has entry for unknown directive '{extra}'")
+
+ for name in sorted(yml_names & valid_names):
+ entry = directives[name]
+
+ set_name = entry.get("parameter_set")
+ if set_name and set_name not in parameter_sets:
+ errors.append(f"'{name}': unknown parameter_set '{set_name}'")
+
+ expected_embed = name in EMBED_CAPABLE_DIRECTIVES
+ if bool(entry.get("embeddable")) != expected_embed:
+ errors.append(f"'{name}': embeddable should be {str(expected_embed).lower()}")
+
+ expected_requires = requirements.get(name, "none")
+ if entry.get("requires") != expected_requires:
+ errors.append(f"'{name}': requires should be '{expected_requires}'")
+
+ valid_args = VALID_ARGUMENTS[name]
+ if isinstance(valid_args, DynamicArguments):
+ if not entry.get("dynamic_parameters"):
+ errors.append(f"'{name}': should set dynamic_parameters: true")
+ continue
+
+ resolved = set(resolve_parameters(entry, parameter_sets))
+ expected_args = set(valid_args)
+ if SHARED_ARGUMENTS[0] in resolved:
+ errors.append(f"'{name}': must not list shared argument '{SHARED_ARGUMENTS[0]}'")
+ for missing in sorted(expected_args - resolved):
+ errors.append(f"'{name}': missing parameter '{missing}'")
+ for extra in sorted(resolved - expected_args):
+ errors.append(f"'{name}': parameter '{extra}' is not accepted by the validator")
+
+ return errors
+
+
+def _table(headers, rows):
+ lines = ["| " + " | ".join(headers) + " |", "|" + "|".join(["---"] * len(headers)) + "|"]
+ for row in rows:
+ lines.append("| " + " | ".join(row) + " |")
+ return "\n".join(lines)
+
+
+def render_markdown(parameter_sets, directives):
+ """Render directives.yml metadata to the Markdown reference."""
+ out = []
+ out.append("# Galaxy Markdown Directive Reference")
+ out.append("")
+ out.append(
+ "Generated from `directives.yml` by `scripts/markdown_directives_doc.py` "
+ "(`make client-gen-markdown-directives`). Do not edit by hand."
+ )
+ out.append("")
+ out.append("## Syntax")
+ out.append("")
+ out.append("**Block** — works for every directive; required in workflow report templates:")
+ out.append("")
+ out.append("````")
+ out.append("```galaxy")
+ out.append("directive_name(arg=value)")
+ out.append("```")
+ out.append("````")
+ out.append("")
+ out.append(
+ "One directive per fenced `galaxy` block. **Inline** (`${galaxy ...}`) works only for the "
+ "[embeddable directives](#embeddable-directives)."
+ )
+ out.append("")
+
+ out.append("## Argument value types")
+ out.append("")
+ present_types = {
+ param.get("type")
+ for entry in directives.values()
+ for param in resolve_parameters(entry, parameter_sets).values()
+ }
+ rows = [[f"`{t}`", TYPE_NOTES[t]] for t in TYPE_ORDER if t in present_types]
+ out.append(_table(["Type", "Meaning"], rows))
+ out.append("")
+
+ out.append("## Addressing contexts")
+ out.append("")
+ out.append("The same directive accepts different parameters depending on how the object is referenced:")
+ out.append("")
+ present_contexts = {
+ param.get("context")
+ for entry in directives.values()
+ for param in resolve_parameters(entry, parameter_sets).values()
+ if param.get("context")
+ }
+ rows = [[f"`{c}`", CONTEXT_NOTES[c]] for c in CONTEXT_ORDER if c in present_contexts]
+ out.append(_table(["Context", "Use"], rows))
+ out.append("")
+
+ out.append("## Universal argument")
+ out.append("")
+ out.append(
+ f'`{SHARED_ARGUMENTS[0]}=""` — wraps a block directive in a collapsible section. '
+ "Valid on every directive."
+ )
+ out.append("")
+
+ by_category = {category: [] for category in CATEGORY_ORDER}
+ for name, entry in directives.items():
+ by_category.setdefault(entry.get("category", "utility"), []).append((name, entry))
+
+ for category in CATEGORY_ORDER:
+ entries = by_category.get(category) or []
+ if not entries:
+ continue
+ out.append("---")
+ out.append("")
+ out.append(f"## {CATEGORY_TITLES[category]}")
+ out.append("")
+ rows = []
+ for name, entry in entries:
+ embed = "✅" if entry.get("embeddable") else ""
+ requires = entry.get("requires", "none")
+ requires_cell = "—" if requires == "none" else f"`{requires}`"
+ rows.append([f"`{name}`", embed, requires_cell, entry.get("renders", "")])
+ out.append(_table(["Directive", "Embed", "Requires", "Renders"], rows))
+ out.append("")
+
+ for name, entry in entries:
+ help_text = _mode_value(entry.get("help"))
+ parameters = resolve_parameters(entry, parameter_sets)
+ dynamic = entry.get("dynamic_parameters")
+ if not help_text and not parameters and not dynamic:
+ continue
+ out.append(f"### `{name}`")
+ out.append("")
+ if help_text:
+ out.append(help_text.replace("%MODE%", "report").strip())
+ out.append("")
+ if dynamic:
+ if not help_text:
+ out.append("Accepts arguments specific to the selected visualization plugin (not validated).")
+ out.append("")
+ elif parameters:
+ param_rows = []
+ for param_name, meta in parameters.items():
+ default = meta.get("default")
+ default_cell = (
+ "" if default is None else f"`{str(default).lower() if isinstance(default, bool) else default}`"
+ )
+ if meta.get("type") == "enum" and meta.get("values"):
+ type_cell = "enum (" + ", ".join(f"`{v}`" for v in meta["values"]) + ")"
+ else:
+ type_cell = f"`{meta.get('type', '')}`"
+ param_rows.append(
+ [
+ f"`{param_name}`",
+ type_cell,
+ f"`{meta['context']}`" if meta.get("context") else "",
+ default_cell,
+ meta.get("description", ""),
+ ]
+ )
+ out.append(_table(["Parameter", "Type", "Context", "Default", "Description"], param_rows))
+ out.append("")
+
+ out.append("---")
+ out.append("")
+ out.append("## Embeddable directives")
+ out.append("")
+ out.append("Inline `${galaxy ...}` syntax is supported only for these directives; all others require block syntax.")
+ out.append("")
+ for name in EMBED_CAPABLE_DIRECTIVES:
+ out.append(f"- `{name}`")
+
+ return "\n".join(out)
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument("--check", action="store_true", help="verify consistency and up-to-date output")
+ parser.add_argument("--output", default=OUTPUT_MD, help="output path for directives.md")
+ args = parser.parse_args()
+
+ parameter_sets, directives = load_directives()
+ requirements = load_requirements()
+
+ errors = consistency_errors(parameter_sets, directives, requirements)
+ if errors:
+ sys.stderr.write("directives.yml is inconsistent with markdown_parse.py:\n")
+ for error in errors:
+ sys.stderr.write(f" - {error}\n")
+ sys.exit(1)
+
+ rendered = render_markdown(parameter_sets, directives) + "\n"
+
+ if args.check:
+ try:
+ with open(args.output) as f:
+ current = f.read()
+ except FileNotFoundError:
+ current = None
+ if current != rendered:
+ sys.stderr.write(f"{args.output} is out of date; regenerate with scripts/markdown_directives_doc.py\n")
+ sys.exit(1)
+ return
+
+ with open(args.output, "w") as f:
+ f.write(rendered)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/test/unit/app/test_markdown_directives_doc.py b/test/unit/app/test_markdown_directives_doc.py
new file mode 100644
index 00000000000..ad4c6923895
--- /dev/null
+++ b/test/unit/app/test_markdown_directives_doc.py
@@ -0,0 +1,30 @@
+"""Guard that directives.yml, the generated directives.md, and the validator stay in sync."""
+
+import importlib.util
+import os
+
+GALAXY_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir))
+SCRIPT_PATH = os.path.join(GALAXY_ROOT, "scripts", "markdown_directives_doc.py")
+
+_spec = importlib.util.spec_from_file_location("markdown_directives_doc", SCRIPT_PATH)
+assert _spec and _spec.loader
+gen = importlib.util.module_from_spec(_spec)
+_spec.loader.exec_module(gen)
+
+
+def test_directives_yml_consistent_with_validator():
+ parameter_sets, directives = gen.load_directives()
+ requirements = gen.load_requirements()
+ errors = gen.consistency_errors(parameter_sets, directives, requirements)
+ assert not errors, "directives.yml drifted from markdown_parse.py:\n" + "\n".join(errors)
+
+
+def test_directives_md_up_to_date():
+ parameter_sets, directives = gen.load_directives()
+ rendered = gen.render_markdown(parameter_sets, directives) + "\n"
+ with open(gen.OUTPUT_MD) as f:
+ current = f.read()
+ assert current == rendered, (
+ "directives.md is out of date; regenerate with "
+ "`python scripts/markdown_directives_doc.py` (or `make client-gen-markdown-directives`)."
+ )