@redpanda-data/docs-extensions-and-macros 3.5.11 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.adoc +3 -3
- package/extensions/generate-rp-connect-info.js +84 -0
- package/macros/rp-connect-components.js +245 -192
- package/package.json +7 -5
package/README.adoc
CHANGED
|
@@ -516,7 +516,7 @@ asciidoc:
|
|
|
516
516
|
|
|
517
517
|
This macro generates a tabbed interface to display Redpanda Connect components by category.
|
|
518
518
|
|
|
519
|
-
The categories are fetched from the `connectCategoriesData` that's generated in the <<
|
|
519
|
+
The categories are fetched from the `connectCategoriesData` that's generated in the <<Component category aggregator>> extension.
|
|
520
520
|
|
|
521
521
|
==== Usage
|
|
522
522
|
|
|
@@ -536,7 +536,7 @@ asciidoc:
|
|
|
536
536
|
|
|
537
537
|
This macro generates a searchable table of all Redpanda Connect components with filters for support and type.
|
|
538
538
|
|
|
539
|
-
The types are fetched from the `flatComponentsData` that's generated in the <<
|
|
539
|
+
The types are fetched from the `flatComponentsData` that's generated in the <<Component category aggregator>> extension.
|
|
540
540
|
|
|
541
541
|
==== Usage
|
|
542
542
|
|
|
@@ -556,7 +556,7 @@ asciidoc:
|
|
|
556
556
|
|
|
557
557
|
This macro generates a dropdown of other supported types for a particular component, allowing users to switch between different types.
|
|
558
558
|
|
|
559
|
-
The types are fetched from the `flatComponentsData` that's generated in the <<
|
|
559
|
+
The types are fetched from the `flatComponentsData` that's generated in the <<Component category aggregator>> extension.
|
|
560
560
|
|
|
561
561
|
==== Usage
|
|
562
562
|
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
const https = require('https');
|
|
3
|
+
const Papa = require('papaparse');
|
|
4
|
+
|
|
5
|
+
const CSV_PATH = 'redpanda_connect.csv'
|
|
6
|
+
const GITHUB_OWNER = 'redpanda-data'
|
|
7
|
+
const GITHUB_REPO = 'rp-connect-docs'
|
|
8
|
+
const GITHUB_REF = 'connect-csv'
|
|
9
|
+
/* const csvUrl = 'https://localhost:3000/csv';
|
|
10
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; */
|
|
11
|
+
|
|
12
|
+
module.exports.register = function ({ config,contentCatalog }) {
|
|
13
|
+
const logger = this.getLogger('redpanda-connect-info-extension');
|
|
14
|
+
|
|
15
|
+
async function loadOctokit() {
|
|
16
|
+
const { Octokit } = await import('@octokit/rest');
|
|
17
|
+
if (!process.env.REDPANDA_GITHUB_TOKEN) return new Octokit()
|
|
18
|
+
return new Octokit({
|
|
19
|
+
auth: process.env.REDPANDA_GITHUB_TOKEN,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
this.once('contentClassified', async ({ siteCatalog, contentCatalog }) => {
|
|
24
|
+
const redpandaConnect = contentCatalog.getComponents().find(component => component.name === 'redpanda-connect')
|
|
25
|
+
const redpandaCloud = contentCatalog.getComponents().find(component => component.name === 'redpanda-cloud')
|
|
26
|
+
if (!redpandaConnect) return
|
|
27
|
+
const pages = contentCatalog.getPages()
|
|
28
|
+
try {
|
|
29
|
+
// Fetch CSV data and parse it
|
|
30
|
+
const csvData = await fetchCSV();
|
|
31
|
+
const parsedData = Papa.parse(csvData, { header: true, skipEmptyLines: true });
|
|
32
|
+
const enrichedData = enrichCsvDataWithUrls(parsedData, pages, logger);
|
|
33
|
+
parsedData.data = enrichedData
|
|
34
|
+
redpandaConnect.latest.asciidoc.attributes.csvData = parsedData;
|
|
35
|
+
redpandaCloud.latest.asciidoc.attributes.csvData = parsedData;
|
|
36
|
+
|
|
37
|
+
} catch (error) {
|
|
38
|
+
logger.error('Error fetching or parsing CSV data:', error.message);
|
|
39
|
+
logger.error(error.stack);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
async function fetchCSV() {
|
|
44
|
+
const octokit = await loadOctokit();
|
|
45
|
+
try {
|
|
46
|
+
const { data: fileContent } = await octokit.rest.repos.getContent({
|
|
47
|
+
owner: GITHUB_OWNER,
|
|
48
|
+
repo: GITHUB_REPO,
|
|
49
|
+
path: CSV_PATH,
|
|
50
|
+
ref: GITHUB_REF,
|
|
51
|
+
});
|
|
52
|
+
return Buffer.from(fileContent.content, 'base64').toString('utf8');
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error('Error fetching Redpanda Connect catalog from GitHub:', error);
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function enrichCsvDataWithUrls(parsedData, connectPages, logger) {
|
|
60
|
+
return parsedData.data.map(row => {
|
|
61
|
+
// Create a new object with trimmed keys and values
|
|
62
|
+
const trimmedRow = Object.fromEntries(
|
|
63
|
+
Object.entries(row).map(([key, value]) => [key.trim(), value.trim()])
|
|
64
|
+
);
|
|
65
|
+
const connector = trimmedRow.connector;
|
|
66
|
+
const type = trimmedRow.type;
|
|
67
|
+
let url = '';
|
|
68
|
+
for (const file of connectPages) {
|
|
69
|
+
const filePath = file.path;
|
|
70
|
+
if (filePath.endsWith(`${connector}.adoc`) && filePath.includes(`pages/${type}s/`)) {
|
|
71
|
+
url = `../${type}s/${connector}`;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (!url) {
|
|
76
|
+
logger.warn(`No matching URL found for connector: ${connector} of type: ${type}`);
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
...trimmedRow,
|
|
80
|
+
url: url
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -1,6 +1,149 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
module.exports.register = function (registry, context) {
|
|
4
|
+
|
|
5
|
+
function filterComponentTable() {
|
|
6
|
+
// Retrieve and standardize filter inputs
|
|
7
|
+
const nameInput = document.getElementById('componentTableSearch').value.trim().toLowerCase();
|
|
8
|
+
const typeFilter = Array.from(document.querySelector('#typeFilter').selectedOptions).map(option => option.value);
|
|
9
|
+
|
|
10
|
+
// Check if the supportFilter element exists
|
|
11
|
+
const supportFilterElement = document.querySelector('#supportFilter');
|
|
12
|
+
const supportFilter = supportFilterElement
|
|
13
|
+
? Array.from(supportFilterElement.selectedOptions).map(option => option.value)
|
|
14
|
+
: [];
|
|
15
|
+
|
|
16
|
+
const table = document.getElementById('componentTable');
|
|
17
|
+
const trs = table.getElementsByTagName('tr');
|
|
18
|
+
|
|
19
|
+
for (let i = 1; i < trs.length; i++) {
|
|
20
|
+
const row = trs[i];
|
|
21
|
+
const nameTd = row.querySelector('td[id^="componentName-"]');
|
|
22
|
+
const typeTd = row.querySelector('td[id^="componentType-"]');
|
|
23
|
+
const supportTd = row.querySelector('td[id^="componentSupport-"]');
|
|
24
|
+
const typeDropdown = typeTd ? typeTd.querySelector('.type-dropdown') : null;
|
|
25
|
+
|
|
26
|
+
if (nameTd && typeTd) {
|
|
27
|
+
const nameText = nameTd.textContent.trim().toLowerCase();
|
|
28
|
+
const typeText = typeTd.textContent.trim().toLowerCase().split(', ').map(item => item.trim());
|
|
29
|
+
const supportText = supportTd ? supportTd.textContent.trim().toLowerCase() : '';
|
|
30
|
+
|
|
31
|
+
// Determine if the row should be shown
|
|
32
|
+
const showRow =
|
|
33
|
+
((!nameInput || nameText.includes(nameInput)) &&
|
|
34
|
+
(typeFilter.length === 0 || typeFilter.some(value => typeText.includes(value))) &&
|
|
35
|
+
(!supportTd || supportFilter.length === 0 || supportFilter.some(value => supportText.includes(value)))
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
row.style.display = showRow ? '' : 'none';
|
|
39
|
+
|
|
40
|
+
if (showRow && typeFilter.length > 0 && typeDropdown) {
|
|
41
|
+
const matchingOption = Array.from(typeDropdown.options).find(option =>
|
|
42
|
+
typeFilter.includes(option.text.toLowerCase())
|
|
43
|
+
);
|
|
44
|
+
if (matchingOption) {
|
|
45
|
+
typeDropdown.value = matchingOption.value;
|
|
46
|
+
updateComponentUrl(typeDropdown, false);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
row.style.display = 'none'; // Hide row if essential cells are missing
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const capitalize = s => s && s[0].toUpperCase() + s.slice(1);
|
|
56
|
+
|
|
57
|
+
function processConnectors(parsedData) {
|
|
58
|
+
return parsedData.data.reduce((connectors, row) => {
|
|
59
|
+
const { connector, commercial_name, type, support_level, is_cloud_supported, is_licensed, url } = row;
|
|
60
|
+
let isCloudSupported = is_cloud_supported === 'y'
|
|
61
|
+
if (!connectors[connector]) {
|
|
62
|
+
connectors[connector] = {
|
|
63
|
+
types: new Map(),
|
|
64
|
+
supportLevels: new Map(),
|
|
65
|
+
isLicensed: is_licensed === 'y' ? 'Yes' : 'No',
|
|
66
|
+
isCloudConnectorSupported : isCloudSupported,
|
|
67
|
+
urls: new Set()
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
connectors[connector].types.set(capitalize(type), { url, isCloudSupported });
|
|
71
|
+
if (url) connectors[connector].urls.add(url);
|
|
72
|
+
if (!connectors[connector].supportLevels.has(support_level)) {
|
|
73
|
+
connectors[connector].supportLevels.set(support_level, new Set());
|
|
74
|
+
}
|
|
75
|
+
connectors[connector].supportLevels.get(support_level).add(commercial_name);
|
|
76
|
+
return connectors;
|
|
77
|
+
}, {});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
function generateConnectorsHTMLTable(connectors, isCloud) {
|
|
82
|
+
return Object.entries(connectors).map(([connector, details], id) => {
|
|
83
|
+
const { types, supportLevels, isCloudConnectorSupported, isLicensed, urls } = details;
|
|
84
|
+
const firstUrl = urls.size > 0 ? urls.values().next().value : null;
|
|
85
|
+
|
|
86
|
+
const typesArray = Array.from(types.entries())
|
|
87
|
+
.map(([type, { url, isCloudSupported }]) => {
|
|
88
|
+
if(isCloud){
|
|
89
|
+
if (isCloudSupported) {
|
|
90
|
+
return url ? `<a href="${url}/">${type}</a>` : `<span>${type}</span>`;
|
|
91
|
+
} else {
|
|
92
|
+
return '';
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else{
|
|
96
|
+
return url ? `<a href="${url}/">${type}</a>` : `<span>${type}</span>`;
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
.filter(item => item !== '');
|
|
100
|
+
|
|
101
|
+
const typesStr = typesArray.join(', ');
|
|
102
|
+
|
|
103
|
+
const supportLevelStr = Array.from(supportLevels.entries())
|
|
104
|
+
.map(([level, names]) => `<p><b>${capitalize(level)}</b>: ${Array.from(names).join(', ')}</p>`)
|
|
105
|
+
.join('');
|
|
106
|
+
|
|
107
|
+
const connectorNameHtml = firstUrl
|
|
108
|
+
? `<code><a href="${firstUrl}/">${connector}</a></code>`
|
|
109
|
+
: `<code><span>${connector}</span></code>`;
|
|
110
|
+
|
|
111
|
+
if (isCloud) {
|
|
112
|
+
if (isCloudConnectorSupported) {
|
|
113
|
+
return `
|
|
114
|
+
<tr id="row-${id}">
|
|
115
|
+
<td class="tableblock halign-left valign-top" id="componentName-${id}">
|
|
116
|
+
<p class="tableblock">${connectorNameHtml}</p>
|
|
117
|
+
</td>
|
|
118
|
+
<td class="tableblock halign-left valign-top" id="componentType-${id}">
|
|
119
|
+
<p class="tableblock">${typesStr}</p>
|
|
120
|
+
</td>
|
|
121
|
+
</tr>`;
|
|
122
|
+
} else {
|
|
123
|
+
return '';
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
return `
|
|
127
|
+
<tr id="row-${id}">
|
|
128
|
+
<td class="tableblock halign-left valign-top" id="componentName-${id}">
|
|
129
|
+
<p class="tableblock">${connectorNameHtml}</p>
|
|
130
|
+
</td>
|
|
131
|
+
<td class="tableblock halign-left valign-top" id="componentType-${id}">
|
|
132
|
+
<p class="tableblock">${typesStr}</p>
|
|
133
|
+
</td>
|
|
134
|
+
<td class="tableblock halign-left valign-top" id="componentSupport-${id}">
|
|
135
|
+
<p class="tableblock">${supportLevelStr.trim()}</p>
|
|
136
|
+
</td>
|
|
137
|
+
<td class="tableblock halign-left valign-top" id="componentLicense-${id}">
|
|
138
|
+
<p class="tableblock">${isLicensed}</p>
|
|
139
|
+
</td>
|
|
140
|
+
</tr>`;
|
|
141
|
+
}
|
|
142
|
+
}).filter(row => row !== '').join(''); // Filter out empty rows
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
4
147
|
let tabsCounter = 1; // Counter for generating unique IDs
|
|
5
148
|
|
|
6
149
|
// Add the category tabs for components
|
|
@@ -16,10 +159,10 @@ module.exports.register = function (registry, context) {
|
|
|
16
159
|
if (!categories) return
|
|
17
160
|
|
|
18
161
|
let tabsHtml = `
|
|
19
|
-
<div id="${currentTabsId}" class="openblock tabs is-sync is-loaded" data-sync-group-id="${type}">
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
162
|
+
<div id="${currentTabsId}" class="openblock tabs is-sync is-loaded" data-sync-group-id="${type}">
|
|
163
|
+
<div class="content">
|
|
164
|
+
<div class="ulist tablist">
|
|
165
|
+
<ul role="tablist">`;
|
|
23
166
|
|
|
24
167
|
categories.forEach((category, index) => {
|
|
25
168
|
tabsHtml += `
|
|
@@ -63,205 +206,106 @@ module.exports.register = function (registry, context) {
|
|
|
63
206
|
const self = this;
|
|
64
207
|
self.named('component_table');
|
|
65
208
|
self.process((parent, target, attrs) => {
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
|
|
209
|
+
const isCloud = attrs["is_cloud"];
|
|
210
|
+
const csvData = context.config?.attributes?.csvData || [];
|
|
211
|
+
const types = new Set();
|
|
212
|
+
const uniqueSupportLevel = new Set();
|
|
213
|
+
|
|
214
|
+
csvData.data.forEach(row => {
|
|
215
|
+
if (row.type) types.add(row.type);
|
|
216
|
+
if (row.support_level) uniqueSupportLevel.add(row.support_level);
|
|
217
|
+
});
|
|
71
218
|
|
|
72
|
-
|
|
73
|
-
|
|
219
|
+
const createOptions = (values) =>
|
|
220
|
+
Array.from(values)
|
|
221
|
+
.map(value => `<option selected value="${value}">${capitalize(value)}</option>`)
|
|
222
|
+
.join('');
|
|
74
223
|
|
|
75
224
|
let tableHtml = `
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
<
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
tableHtml +=
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
<option value="">All Types</option>`;
|
|
225
|
+
<div class="table-filters">
|
|
226
|
+
<input class="table-search" type="text" id="componentTableSearch" onkeyup="filterComponentTable()" placeholder="Search for components...">
|
|
227
|
+
<label for="typeFilter">Type:</label>
|
|
228
|
+
<select multiple class="type-dropdown" id="typeFilter" onchange="filterComponentTable()">
|
|
229
|
+
${createOptions(types)}
|
|
230
|
+
</select>
|
|
231
|
+
`
|
|
232
|
+
if (!isCloud) {
|
|
233
|
+
tableHtml += `
|
|
234
|
+
<br><label for="supportFilter" id="labelForSupportFilter">Support:</label>
|
|
235
|
+
<select multiple class="type-dropdown" id="supportFilter" onchange="filterComponentTable()">
|
|
236
|
+
${createOptions(uniqueSupportLevel)}
|
|
237
|
+
</select>`
|
|
238
|
+
}
|
|
91
239
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
240
|
+
tableHtml += `</div>
|
|
241
|
+
<table class="tableblock frame-all grid-all stripes-even no-clip stretch component-table" id="componentTable">
|
|
242
|
+
<colgroup>
|
|
243
|
+
${isCloud
|
|
244
|
+
? '<col style="width: 50%;"><col style="width: 50%;">'
|
|
245
|
+
: '<col style="width: 25%;"><col style="width: 25%;"><col style="width: 25%;"><col style="width: 25%;">'
|
|
246
|
+
}
|
|
247
|
+
</colgroup>
|
|
248
|
+
<thead>
|
|
249
|
+
<tr>
|
|
250
|
+
<th class="tableblock halign-left valign-top">Name</th>
|
|
251
|
+
<th class="tableblock halign-left valign-top">Connector Type</th>
|
|
252
|
+
${isCloud ? '' : `
|
|
253
|
+
<th class="tableblock halign-left valign-top">Support Level</th>
|
|
254
|
+
<th class="tableblock halign-left valign-top">Enterprise Licensed</th>`}
|
|
255
|
+
</tr>
|
|
256
|
+
</thead>
|
|
257
|
+
<tbody>
|
|
258
|
+
${generateConnectorsHTMLTable(processConnectors(csvData), isCloud)}
|
|
259
|
+
</tbody>
|
|
260
|
+
</table>
|
|
261
|
+
<script>
|
|
262
|
+
${filterComponentTable.toString()}
|
|
97
263
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
<col style="width: 33.3%;">
|
|
104
|
-
<col style="width: 33.3%;">
|
|
105
|
-
<col style="width: 33.3%;">
|
|
106
|
-
</colgroup>
|
|
107
|
-
<thead>
|
|
108
|
-
<tr>
|
|
109
|
-
<th class="tableblock halign-left valign-top">Connector</th>
|
|
110
|
-
<th class="tableblock halign-left valign-top">Support</th>
|
|
111
|
-
<th class="tableblock halign-left valign-top">Type</th>
|
|
112
|
-
</tr>
|
|
113
|
-
</thead>
|
|
114
|
-
<tbody>`;
|
|
115
|
-
|
|
116
|
-
flatComponentsData.forEach(item => {
|
|
117
|
-
const commonName = item.originalName !== item.name ? ` <small>(${item.name})</small>`: '';
|
|
118
|
-
const isEnterprise = item.enterprise ? '<span class="enterprise-label" title="Requires an Enterprise Edition license">Enterprise</span>' : '';
|
|
119
|
-
if (driverSupportData[item.originalName]) {
|
|
120
|
-
const drivers = driverSupportData[item.originalName].split(', ');
|
|
121
|
-
drivers.forEach(driverSupportPair => {
|
|
122
|
-
const [driver, support] = driverSupportPair.split('=');
|
|
123
|
-
// Find the common name
|
|
124
|
-
const driverNameEntry = driverNameMap.find(driverItem => driverItem.key === driver)
|
|
125
|
-
const driverName = driverNameEntry ? driverNameEntry.name : driver
|
|
126
|
-
|
|
127
|
-
// Filter for types of input, processor, and output only
|
|
128
|
-
const filteredTypes = item.types.filter(typeOption => ['input', 'processor', 'output'].includes(typeOption.type));
|
|
129
|
-
if (filteredTypes.length > 0) {
|
|
130
|
-
const typeDropdown = filteredTypes.length > 1
|
|
131
|
-
? `<select class="type-dropdown" onchange="updateComponentUrl(this, true)">
|
|
132
|
-
${filteredTypes.map(typeOption => `<option value="${typeOption.url}">${typeOption.type.charAt(0).toUpperCase() + typeOption.type.slice(1)}</option>`).join('')}
|
|
133
|
-
</select>`
|
|
134
|
-
: filteredTypes[0].type.charAt(0).toUpperCase() + filteredTypes[0].type.slice(1);
|
|
135
|
-
|
|
136
|
-
tableHtml += `
|
|
137
|
-
<tr>
|
|
138
|
-
<td class="tableblock halign-left valign-top"><p class="tableblock"><p class="enterprise-label-container">${isEnterprise}</p><code><a href="${filteredTypes[0].url}">${item.originalName}</a></code> ${commonName}<br><span style="font-size:0.9rem;">${driverName} driver</span></p></td>
|
|
139
|
-
<td class="tableblock halign-left valign-top"><p class="tableblock">${support.charAt(0).toUpperCase() + support.slice(1)}</p></td>
|
|
140
|
-
<td class="tableblock halign-left valign-top"><p class="tableblock">${typeDropdown}</p></td>
|
|
141
|
-
</tr>`;
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
} else if (cacheSupportData[item.originalName]) {
|
|
145
|
-
const caches = cacheSupportData[item.originalName].split(', ');
|
|
146
|
-
caches.forEach(cacheSupportPair => {
|
|
147
|
-
const [cache, support] = cacheSupportPair.split('=');
|
|
148
|
-
// Find the common name
|
|
149
|
-
const cacheNameEntry = cacheNameMap.find(cacheItem => cacheItem.key === cache)
|
|
150
|
-
const cacheName = cacheNameEntry ? cacheNameEntry.name : cache
|
|
151
|
-
|
|
152
|
-
// Filter for types of input, processor, and output only
|
|
153
|
-
const filteredTypes = item.types.filter(typeOption => ['input', 'processor', 'output'].includes(typeOption.type));
|
|
154
|
-
if (filteredTypes.length > 0) {
|
|
155
|
-
const typeDropdown = filteredTypes.length > 1
|
|
156
|
-
? `<select class="type-dropdown" onchange="updateComponentUrl(this, true)">
|
|
157
|
-
${filteredTypes.map(typeOption => `<option value="${typeOption.url}">${typeOption.type.charAt(0).toUpperCase() + typeOption.type.slice(1)}</option>`).join('')}
|
|
158
|
-
</select>`
|
|
159
|
-
: filteredTypes[0].type.charAt(0).toUpperCase() + filteredTypes[0].type.slice(1);
|
|
160
|
-
|
|
161
|
-
tableHtml += `
|
|
162
|
-
<tr>
|
|
163
|
-
<td class="tableblock halign-left valign-top"><p class="tableblock"><p class="enterprise-label-container">${isEnterprise}</p><code><a href="${filteredTypes[0].url}">${item.originalName}</a></code> ${commonName}<br><span style="font-size:0.9rem;">${cacheName}</span></p></td>
|
|
164
|
-
<td class="tableblock halign-left valign-top"><p class="tableblock">${support.charAt(0).toUpperCase() + support.slice(1)}</p></td>
|
|
165
|
-
<td class="tableblock halign-left valign-top"><p class="tableblock">${typeDropdown}</p></td>
|
|
166
|
-
</tr>`;
|
|
167
|
-
}
|
|
264
|
+
function getQueryParams() {
|
|
265
|
+
const params = {};
|
|
266
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
267
|
+
searchParams.forEach((value, key) => {
|
|
268
|
+
params[key] = value;
|
|
168
269
|
});
|
|
169
|
-
|
|
170
|
-
// Filter for types of input, processor, and output only
|
|
171
|
-
const filteredTypes = item.types.filter(typeOption => ['input', 'processor', 'output'].includes(typeOption.type));
|
|
172
|
-
if (filteredTypes.length > 0) {
|
|
173
|
-
const typeDropdown = filteredTypes.length > 1
|
|
174
|
-
? `<select class="type-dropdown" onchange="updateComponentUrl(this, true)">
|
|
175
|
-
${filteredTypes.map(typeObj => `<option value="${typeObj.url}">${typeObj.type.charAt(0).toUpperCase() + typeObj.type.slice(1)}</option>`).join('')}
|
|
176
|
-
</select>`
|
|
177
|
-
: filteredTypes[0].type.charAt(0).toUpperCase() + filteredTypes[0].type.slice(1);
|
|
178
|
-
|
|
179
|
-
tableHtml += `
|
|
180
|
-
<tr>
|
|
181
|
-
<td class="tableblock halign-left valign-top"><p class="tableblock"><p class="enterprise-label-container">${isEnterprise}</p><code><a href="${filteredTypes[0].url}">${item.originalName}</a></code> ${commonName}</p></td>
|
|
182
|
-
<td class="tableblock halign-left valign-top"><p class="tableblock">${item.support.charAt(0).toUpperCase() + item.support.slice(1)}</p></td>
|
|
183
|
-
<td class="tableblock halign-left valign-top"><p class="tableblock">${typeDropdown}</p></td>
|
|
184
|
-
</tr>`;
|
|
185
|
-
}
|
|
270
|
+
return params;
|
|
186
271
|
}
|
|
187
|
-
});
|
|
188
272
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const nameInput = document.getElementById('componentTableSearch').value.toLowerCase();
|
|
195
|
-
const supportFilter = document.getElementById('supportFilter').value;
|
|
196
|
-
const typeFilter = document.getElementById('typeFilter').value;
|
|
197
|
-
const table = document.getElementById('componentTable');
|
|
198
|
-
const trs = table.getElementsByTagName('tr');
|
|
199
|
-
|
|
200
|
-
for (let i = 1; i < trs.length; i++) {
|
|
201
|
-
const nameTd = trs[i].getElementsByTagName('td')[0];
|
|
202
|
-
const supportTd = trs[i].getElementsByTagName('td')[1];
|
|
203
|
-
const typeTd = trs[i].getElementsByTagName('td')[2];
|
|
204
|
-
const typeDropdown = typeTd.querySelector('.type-dropdown');
|
|
205
|
-
let showRow =
|
|
206
|
-
(!nameInput || nameTd.textContent.toLowerCase().includes(nameInput)) &&
|
|
207
|
-
(!supportFilter || supportTd.textContent.toLowerCase() === supportFilter.toLowerCase()) &&
|
|
208
|
-
(!typeFilter || (typeDropdown ? Array.from(typeDropdown.options).some(option => option.text.toLowerCase() === typeFilter.toLowerCase()) : typeTd.textContent.toLowerCase().includes(typeFilter.toLowerCase())));
|
|
209
|
-
|
|
210
|
-
trs[i].style.display = showRow ? '' : 'none';
|
|
211
|
-
|
|
212
|
-
if (showRow && typeFilter && typeDropdown) {
|
|
213
|
-
const matchingOption = Array.from(typeDropdown.options).find(option => option.text.toLowerCase() === typeFilter.toLowerCase());
|
|
214
|
-
typeDropdown.value = matchingOption.value;
|
|
215
|
-
updateComponentUrl(typeDropdown, false);
|
|
273
|
+
function updateComponentUrl(select, redirect) {
|
|
274
|
+
const anchor = select.closest('tr').querySelector('a');
|
|
275
|
+
anchor.href = select.value;
|
|
276
|
+
if (redirect) {
|
|
277
|
+
window.location.href = select.value; // Redirect to the new URL
|
|
216
278
|
}
|
|
217
279
|
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
function getQueryParams() {
|
|
221
|
-
const params = {};
|
|
222
|
-
const searchParams = new URLSearchParams(window.location.search);
|
|
223
|
-
searchParams.forEach((value, key) => {
|
|
224
|
-
params[key] = value;
|
|
225
|
-
});
|
|
226
|
-
return params;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
function capitalizeFirstLetter(string) {
|
|
230
|
-
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
function updateComponentUrl(select, redirect) {
|
|
234
|
-
const anchor = select.closest('tr').querySelector('a');
|
|
235
|
-
anchor.href = select.value;
|
|
236
|
-
if (redirect) {
|
|
237
|
-
window.location.href = select.value; // Redirect to the new URL
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
280
|
|
|
241
|
-
|
|
242
|
-
|
|
281
|
+
// Initialize Choices.js for type dropdowns
|
|
282
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
243
283
|
const params = getQueryParams();
|
|
244
284
|
if (params.search) {
|
|
245
285
|
document.getElementById('componentTableSearch').value = params.search;
|
|
246
286
|
}
|
|
247
|
-
if (params.support) {
|
|
248
|
-
document.getElementById('supportFilter').value = params.support;
|
|
249
|
-
}
|
|
250
287
|
if (params.type) {
|
|
251
288
|
document.getElementById('typeFilter').value = params.type;
|
|
252
289
|
}
|
|
290
|
+
if (params.support) {
|
|
291
|
+
document.getElementById('supportFilter').value = params.support;
|
|
292
|
+
}
|
|
293
|
+
|
|
253
294
|
filterComponentTable();
|
|
254
295
|
const typeDropdowns = document.querySelectorAll('.type-dropdown');
|
|
255
296
|
typeDropdowns.forEach(dropdown => {
|
|
256
|
-
new Choices(dropdown, {
|
|
297
|
+
new Choices(dropdown, {
|
|
298
|
+
searchEnabled: false,
|
|
299
|
+
allowHTML: true,
|
|
300
|
+
removeItemButton: true });
|
|
301
|
+
});
|
|
257
302
|
});
|
|
258
|
-
|
|
259
|
-
</script>`;
|
|
303
|
+
</script>`;
|
|
260
304
|
|
|
261
305
|
return self.createBlock(parent, 'pass', tableHtml);
|
|
262
306
|
});
|
|
263
307
|
});
|
|
264
|
-
|
|
308
|
+
|
|
265
309
|
registry.blockMacro(function () {
|
|
266
310
|
const self = this;
|
|
267
311
|
self.named('component_type_dropdown');
|
|
@@ -274,16 +318,31 @@ module.exports.register = function (registry, context) {
|
|
|
274
318
|
return self.createBlock(parent, 'pass', '');
|
|
275
319
|
}
|
|
276
320
|
|
|
277
|
-
const
|
|
278
|
-
const
|
|
321
|
+
const csvData = context.config?.attributes?.csvData || [];
|
|
322
|
+
const componentRows = csvData.data.filter(row => row.connector.trim().toLowerCase() === name.trim().toLowerCase());
|
|
279
323
|
|
|
280
|
-
if (
|
|
324
|
+
if (componentRows.length === 0) {
|
|
281
325
|
return self.createBlock(parent, 'pass', '');
|
|
282
326
|
}
|
|
283
327
|
|
|
284
|
-
//
|
|
328
|
+
// Process types from CSV
|
|
329
|
+
const types = componentRows.map(row => ({
|
|
330
|
+
type: row.type.trim(),
|
|
331
|
+
support: row.support_level.trim(),
|
|
332
|
+
url: row.url ? row.url.trim() : '#'
|
|
333
|
+
}));
|
|
334
|
+
|
|
335
|
+
// Move the current page's type to the first position in the dropdown
|
|
336
|
+
const sortedTypes = [...types];
|
|
337
|
+
const currentTypeIndex = sortedTypes.findIndex(typeObj => typeObj.type === type);
|
|
338
|
+
if (currentTypeIndex !== -1) {
|
|
339
|
+
const [currentType] = sortedTypes.splice(currentTypeIndex, 1);
|
|
340
|
+
sortedTypes.unshift(currentType);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Check if the component requires an Enterprise license (based on support level)
|
|
285
344
|
let enterpriseAdmonition = '';
|
|
286
|
-
if (
|
|
345
|
+
if (componentRows.some(row => row.support_level.toLowerCase() === 'enterprise')) {
|
|
287
346
|
enterpriseAdmonition = `
|
|
288
347
|
<div class="admonitionblock note">
|
|
289
348
|
<table>
|
|
@@ -303,20 +362,14 @@ module.exports.register = function (registry, context) {
|
|
|
303
362
|
</div>`;
|
|
304
363
|
}
|
|
305
364
|
|
|
306
|
-
//
|
|
307
|
-
const sortedTypes = [...component.types];
|
|
308
|
-
const currentTypeIndex = sortedTypes.findIndex(typeObj => typeObj.type === type);
|
|
309
|
-
if (currentTypeIndex !== -1) {
|
|
310
|
-
const [currentType] = sortedTypes.splice(currentTypeIndex, 1);
|
|
311
|
-
sortedTypes.unshift(currentType);
|
|
312
|
-
}
|
|
365
|
+
// Create the dropdown for types
|
|
313
366
|
let typeDropdown = '';
|
|
314
|
-
if (
|
|
367
|
+
if (sortedTypes.length > 1) {
|
|
315
368
|
typeDropdown = `
|
|
316
369
|
<div class="page-type-dropdown">
|
|
317
370
|
<p>Type: </p>
|
|
318
371
|
<select class="type-dropdown" onchange="window.location.href=this.value">
|
|
319
|
-
${sortedTypes.map(typeObj => `<option value="
|
|
372
|
+
${sortedTypes.map(typeObj => `<option value="../${typeObj.url}/" data-support="${typeObj.support}">${capitalize(typeObj.type)}</option>`).join('')}
|
|
320
373
|
</select>
|
|
321
374
|
</div>
|
|
322
375
|
<script>
|
|
@@ -332,4 +385,4 @@ module.exports.register = function (registry, context) {
|
|
|
332
385
|
return self.createBlock(parent, 'pass', typeDropdown + enterpriseAdmonition);
|
|
333
386
|
});
|
|
334
387
|
});
|
|
335
|
-
};
|
|
388
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redpanda-data/docs-extensions-and-macros",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "Antora extensions and macros developed for Redpanda documentation.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"antora",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
},
|
|
32
32
|
"./extensions/replace-attributes-in-attachments": "./extensions/replace-attributes-in-attachments.js",
|
|
33
33
|
"./extensions/generate-rp-connect-categories": "./extensions/generate-rp-connect-categories.js",
|
|
34
|
+
"./extensions/generate-rp-connect-info": "./extensions/generate-rp-connect-info.js",
|
|
34
35
|
"./extensions/add-global-attributes": "./extensions/add-global-attributes.js",
|
|
35
36
|
"./extensions/version-fetcher/set-latest-version": "./extensions/version-fetcher/set-latest-version.js",
|
|
36
37
|
"./extensions/modify-connect-tag-playbook": "./extensions/modify-connect-tag-playbook.js",
|
|
@@ -57,6 +58,9 @@
|
|
|
57
58
|
"url": "git+https://github.com/redpanda-data/docs-extensions-and-macros"
|
|
58
59
|
},
|
|
59
60
|
"dependencies": {
|
|
61
|
+
"@octokit/core": "^6.1.2",
|
|
62
|
+
"@octokit/plugin-retry": "^7.1.1",
|
|
63
|
+
"@octokit/rest": "^21.0.1",
|
|
60
64
|
"algoliasearch": "^4.17.0",
|
|
61
65
|
"chalk": "4.1.2",
|
|
62
66
|
"gulp": "^4.0.2",
|
|
@@ -65,10 +69,8 @@
|
|
|
65
69
|
"js-yaml": "^4.1.0",
|
|
66
70
|
"lodash": "^4.17.21",
|
|
67
71
|
"node-html-parser": "5.4.2-0",
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"@octokit/plugin-retry": "^7.1.1",
|
|
71
|
-
"@octokit/rest": "^21.0.1"
|
|
72
|
+
"papaparse": "^5.4.1",
|
|
73
|
+
"semver": "^7.6.0"
|
|
72
74
|
},
|
|
73
75
|
"devDependencies": {
|
|
74
76
|
"@antora/cli": "3.1.4",
|