Skip to content

Commit 9f5c1b5

Browse files
slusarzcmouse
authored andcommitted
doveadm: Output HTTP API examples for each command
Dynamically generate this data only when the user clicks on the API documentation for a command, otherwise we are creating giant pages which will noticeably slowdown browsing. Additionally, add the command name to the HTTP output as well, since that was previously missing (although it can be found in the request example, it is not clearly labeled there).
1 parent 2e0bbf8 commit 9f5c1b5

File tree

5 files changed

+121
-24
lines changed

5 files changed

+121
-24
lines changed

components/DoveadmComponent.vue

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup>
22
import { data } from '../lib/data/doveadm.data.js'
3+
import { ref } from 'vue'
34
45
/* Properties for this component:
56
* 'plugin' (string): Filter by the plugin property.
@@ -16,6 +17,11 @@ const d = Object.fromEntries(Object.entries(data.doveadm).filter(([k, v]) =>
1617
((v.plugin && v.plugin == props.tag) ||
1718
(v.tags.includes(props.tag))))
1819
).sort())
20+
21+
let apiComponent = ref({})
22+
function httpApiClick(k) {
23+
apiComponent.value[k] = 'DoveadmHttpApiComponent'
24+
}
1925
</script>
2026

2127
<style scoped>
@@ -115,38 +121,17 @@ const d = Object.fromEntries(Object.entries(data.doveadm).filter(([k, v]) =>
115121
<td><code>{{ elem.flag }}</code></td>
116122
<td>{{ elem.type }}</td>
117123
<td v-html="elem.text" />
118-
<td><code v-if="elem.example">{{ elem.example }}</code></td>
124+
<td><code v-if="elem.example !== undefined">{{ JSON.stringify(elem.example) }}</code></td>
119125
</tr>
120126
</template>
121127
</tbody>
122128
</table>
123129
</div>
124130
</div>
125131

126-
<details v-if="v.args" class="details custom-block">
132+
<details v-if="v.args" @click.capture.once="httpApiClick(k)" class="details custom-block">
127133
<summary v-html="data.http_api_link" />
128-
<div>
129-
<table>
130-
<thead>
131-
<tr>
132-
<th>Parameter</th>
133-
<th>Type</th>
134-
<th>Description</th>
135-
<th>Example</th>
136-
</tr>
137-
</thead>
138-
<tbody>
139-
<template v-for="elem in v.args">
140-
<tr>
141-
<td><code>{{ elem.param }}</code></td>
142-
<td>{{ elem.type }}</td>
143-
<td v-html="elem.text" />
144-
<td><code v-if="elem.example">{{ elem.example }}</code></td>
145-
</tr>
146-
</template>
147-
</tbody>
148-
</table>
149-
</div>
134+
<component v-if="apiComponent[k]" :is="apiComponent[k]" :data="v" />
150135
</details>
151136

152137
</article>
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<script setup>
2+
/* Properties for this component:
3+
* 'data' (object): The command argument data.
4+
*
5+
* Note: Clipboard behavior is handled by re-using the Vitepress code.
6+
*/
7+
const props = defineProps(['data'])
8+
const d = props.data
9+
10+
const args = {}
11+
for (let elem of d.args.filter(e => e.example !== undefined && !e.cli_only)) {
12+
args[elem.param] = elem.example
13+
}
14+
15+
const jsonReq =
16+
[
17+
[
18+
d.http_cmd,
19+
args,
20+
"tag1"
21+
]
22+
]
23+
</script>
24+
25+
<template>
26+
<div>
27+
<p class="custom-block-title">
28+
Command Name: <code>{{ d.http_cmd }}</code>
29+
</p>
30+
31+
<table>
32+
<thead>
33+
<tr>
34+
<th>Parameter</th>
35+
<th>Type</th>
36+
<th>Description</th>
37+
<th>Example</th>
38+
</tr>
39+
</thead>
40+
<tbody>
41+
<template v-for="elem in d.args">
42+
<tr v-if="!elem.cli_only">
43+
<td><code>{{ elem.param }}</code></td>
44+
<td>{{ elem.type }}</td>
45+
<td v-html="elem.text" />
46+
<td><code v-if="elem.example">{{ JSON.stringify(elem.example) }}</code></td>
47+
</tr>
48+
</template>
49+
</tbody>
50+
</table>
51+
52+
<p class="custom-block-title">Example Request Payload</p>
53+
54+
<div class="language- vp-adaptive-theme">
55+
<button class="copy" title="Copy" />
56+
<span class="lang"></span>
57+
<pre><code>{{ JSON.stringify(jsonReq, null, 4) }}</code></pre>
58+
</div>
59+
60+
<p class="custom-block-title">Example Curl Request (using Dovecot API Key)</p>
61+
62+
<div class="language- vp-adaptive-theme">
63+
<button class="copy" title="Copy" />
64+
<span class="lang"></span>
65+
<pre><code>curl -X POST -H "Authorization: X-Dovecot-API &lt;base64 encoded dovecot_api_key&gt;" -H "Content-Type: application/json" -d '{{ JSON.stringify(jsonReq) }}' http://example.com:8080/doveadm/v1</code></pre>
66+
</div>
67+
68+
<p class="custom-block-title">Example Curl Request (using Doveadm Password)</p>
69+
70+
<div class="language- vp-adaptive-theme">
71+
<button class="copy" title="Copy" />
72+
<span class="lang"></span>
73+
<pre><code>curl -X POST -u doveadm:secretpassword -H "Content-Type: application/json" -d '{{ JSON.stringify(jsonReq) }}' http://example.com:8080/doveadm/v1</code></pre>
74+
</div>
75+
76+
<p class="custom-block-title">Example Wget Request (using Dovecot API Key)</p>
77+
78+
<div class="language- vp-adaptive-theme">
79+
<button class="copy" title="Copy" />
80+
<span class="lang"></span>
81+
<pre><code>wget --header="Authorization: X-Dovecot-API &lt;base64 encoded dovecot_api_key&gt;" --header="Content-Type: application/json" --post-data='{{ JSON.stringify(jsonReq) }}' --output-document - http://example.com:8080/doveadm/v1</code></pre>
82+
</div>
83+
84+
<p class="custom-block-title">Example Wget Request (using Doveadm Password)</p>
85+
86+
<div class="language- vp-adaptive-theme">
87+
<button class="copy" title="Copy" />
88+
<span class="lang"></span>
89+
<pre><code>wget --header="Content-Type: application/json" --user=doveadm --password=password --auth-no-challenge --post-data='{{ JSON.stringify(jsonReq) }}' --output-document - http://example.com:8080/doveadm/v1</code></pre>
90+
</div>
91+
</div>
92+
</template>

lib/data/doveadm.data.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { doveadm_arg_types, doveadm_flag_types, getDoveadmCmdLine } from '../doveadm.js'
22
import { getVitepressMd } from '../markdown.js'
33
import { addWatchPaths, loadData, normalizeArrayData } from '../utility.js'
4+
import camelCase from 'camelcase'
45
import slugify from '@sindresorhus/slugify'
56

67
const doveadm_userargs = {
@@ -125,6 +126,7 @@ async function normalizeDoveadm(doveadm) {
125126
if (!v2.hidden) {
126127
args.push({
127128
/* Undefined examples will resolve to undefined. */
129+
cli_only: v2.cli_only,
128130
example: v2.example,
129131
flag: v2.cli ? '-' + v2.cli : (v2.positional ? k2 : '--' + k2),
130132
param: argToHttpParam(k2),
@@ -138,6 +140,9 @@ async function normalizeDoveadm(doveadm) {
138140
if (!v.args || !v.args.length) {
139141
delete v['args']
140142
}
143+
144+
/* HTTP API info. */
145+
v.http_cmd = camelCase(k)
141146
}
142147

143148
return {

package-lock.json

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"devDependencies": {
33
"@sindresorhus/slugify": "^2.2.1",
4+
"camelcase": "^8.0.0",
45
"commander": "^12.1.0",
56
"dayjs": "^1.11.13",
67
"fast-glob": "^3.3.2",

0 commit comments

Comments
 (0)