@redpanda-data/docs-extensions-and-macros 3.7.0 → 3.7.1
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.
|
@@ -1,17 +1,11 @@
|
|
|
1
|
-
/* Example use in the playbook
|
|
2
|
-
* antora:
|
|
3
|
-
extensions:
|
|
4
|
-
* - require: ./extensions/generate-rp-connect-info.js
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
1
|
'use strict'
|
|
8
2
|
const fs = require('fs');
|
|
9
3
|
const path = require('path');
|
|
10
4
|
const Papa = require('papaparse');
|
|
11
5
|
|
|
12
|
-
const CSV_PATH = '
|
|
6
|
+
const CSV_PATH = 'internal/plugins/info.csv'
|
|
13
7
|
const GITHUB_OWNER = 'redpanda-data'
|
|
14
|
-
const GITHUB_REPO = '
|
|
8
|
+
const GITHUB_REPO = 'connect'
|
|
15
9
|
const GITHUB_REF = 'main'
|
|
16
10
|
|
|
17
11
|
module.exports.register = function ({ config }) {
|
|
@@ -28,6 +22,7 @@ module.exports.register = function ({ config }) {
|
|
|
28
22
|
this.once('contentClassified', async ({ contentCatalog }) => {
|
|
29
23
|
const redpandaConnect = contentCatalog.getComponents().find(component => component.name === 'redpanda-connect');
|
|
30
24
|
const redpandaCloud = contentCatalog.getComponents().find(component => component.name === 'redpanda-cloud');
|
|
25
|
+
const preview = contentCatalog.getComponents().find(component => component.name === 'preview');
|
|
31
26
|
if (!redpandaConnect) return;
|
|
32
27
|
const pages = contentCatalog.getPages();
|
|
33
28
|
|
|
@@ -35,7 +30,7 @@ module.exports.register = function ({ config }) {
|
|
|
35
30
|
// Fetch CSV data (either from local file or GitHub)
|
|
36
31
|
const csvData = await fetchCSV(config.csvpath);
|
|
37
32
|
const parsedData = Papa.parse(csvData, { header: true, skipEmptyLines: true });
|
|
38
|
-
const enrichedData =
|
|
33
|
+
const enrichedData = translateCsvData(parsedData, pages, logger);
|
|
39
34
|
parsedData.data = enrichedData;
|
|
40
35
|
|
|
41
36
|
if (redpandaConnect) {
|
|
@@ -44,6 +39,10 @@ module.exports.register = function ({ config }) {
|
|
|
44
39
|
if (redpandaCloud) {
|
|
45
40
|
redpandaCloud.latest.asciidoc.attributes.csvData = parsedData;
|
|
46
41
|
}
|
|
42
|
+
// For previewing the data on our extensions site
|
|
43
|
+
if (preview) {
|
|
44
|
+
preview.latest.asciidoc.attributes.csvData = parsedData;
|
|
45
|
+
}
|
|
47
46
|
|
|
48
47
|
} catch (error) {
|
|
49
48
|
logger.error('Error fetching or parsing CSV data:', error.message);
|
|
@@ -82,28 +81,82 @@ module.exports.register = function ({ config }) {
|
|
|
82
81
|
}
|
|
83
82
|
}
|
|
84
83
|
|
|
85
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Translates the parsed CSV data into our expected format.
|
|
86
|
+
* If "enterprise" is found in the `support` column, it is replaced with "certified" in the output.
|
|
87
|
+
*
|
|
88
|
+
* @param {object} parsedData - The CSV data parsed into an object.
|
|
89
|
+
* @param {array} pages - The list of pages to map the URLs (used for enrichment with URLs).
|
|
90
|
+
* @param {object} logger - The logger used for error handling.
|
|
91
|
+
*
|
|
92
|
+
* @returns {array} - The translated and enriched data.
|
|
93
|
+
*/
|
|
94
|
+
function translateCsvData(parsedData, pages, logger) {
|
|
86
95
|
return parsedData.data.map(row => {
|
|
87
96
|
// Create a new object with trimmed keys and values
|
|
88
97
|
const trimmedRow = Object.fromEntries(
|
|
89
98
|
Object.entries(row).map(([key, value]) => [key.trim(), value.trim()])
|
|
90
99
|
);
|
|
91
|
-
|
|
100
|
+
|
|
101
|
+
// Map fields from the trimmed row to the desired output
|
|
102
|
+
const connector = trimmedRow.name;
|
|
92
103
|
const type = trimmedRow.type;
|
|
93
|
-
|
|
94
|
-
|
|
104
|
+
const commercial_name = trimmedRow.commercial_name;
|
|
105
|
+
const available_connect_version = trimmedRow.version;
|
|
106
|
+
const deprecated = trimmedRow.deprecated.toLowerCase() === 'y' ? 'y' : 'n';
|
|
107
|
+
const is_cloud_supported = trimmedRow.cloud.toLowerCase() === 'y' ? 'y' : 'n';
|
|
108
|
+
const cloud_ai = trimmedRow.cloud_with_gpu.toLowerCase() === 'y' ? 'y' : 'n';
|
|
109
|
+
// Handle enterprise to certified conversion and set enterprise license flag
|
|
110
|
+
const originalSupport = trimmedRow.support.toLowerCase();
|
|
111
|
+
const support_level = originalSupport === 'enterprise' ? 'certified' : originalSupport;
|
|
112
|
+
const is_licensed = originalSupport === 'enterprise' ? 'Yes' : 'No';
|
|
113
|
+
|
|
114
|
+
// Redpanda Connect and Cloud enrichment URLs
|
|
115
|
+
let redpandaConnectUrl = '';
|
|
116
|
+
let redpandaCloudUrl = '';
|
|
117
|
+
|
|
118
|
+
// Look for both Redpanda Connect and Cloud URLs
|
|
119
|
+
for (const file of pages) {
|
|
120
|
+
const component = file.src.component;
|
|
95
121
|
const filePath = file.path;
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
122
|
+
|
|
123
|
+
if (
|
|
124
|
+
component === 'redpanda-connect' &&
|
|
125
|
+
filePath.endsWith(`/${connector}.adoc`) &&
|
|
126
|
+
filePath.includes(`pages/${type}s/`)
|
|
127
|
+
) {
|
|
128
|
+
redpandaConnectUrl = file.pub.url;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Only check for Redpanda Cloud URLs if cloud is supported
|
|
132
|
+
if (
|
|
133
|
+
is_cloud_supported === 'y' &&
|
|
134
|
+
component === 'redpanda-cloud' &&
|
|
135
|
+
filePath.endsWith(`/${connector}.adoc`) &&
|
|
136
|
+
filePath.includes(`${type}s/`)
|
|
137
|
+
) {
|
|
138
|
+
redpandaCloudUrl = file.pub.url;
|
|
99
139
|
}
|
|
100
140
|
}
|
|
101
|
-
|
|
102
|
-
|
|
141
|
+
|
|
142
|
+
// Log a warning if neither URL was found (only warn for missing cloud if it should support cloud)
|
|
143
|
+
if (!redpandaConnectUrl && (!redpandaCloudUrl && is_cloud_supported === 'y')) {
|
|
144
|
+
logger.info(`Docs missing for: ${connector} of type: ${type}`);
|
|
103
145
|
}
|
|
146
|
+
|
|
147
|
+
// Return the translated and enriched row
|
|
104
148
|
return {
|
|
105
|
-
|
|
106
|
-
|
|
149
|
+
connector,
|
|
150
|
+
type,
|
|
151
|
+
commercial_name,
|
|
152
|
+
available_connect_version,
|
|
153
|
+
support_level, // "enterprise" is replaced with "certified"
|
|
154
|
+
deprecated,
|
|
155
|
+
is_cloud_supported,
|
|
156
|
+
cloud_ai,
|
|
157
|
+
is_licensed, // "Yes" if the original support level was "enterprise"
|
|
158
|
+
redpandaConnectUrl,
|
|
159
|
+
redpandaCloudUrl,
|
|
107
160
|
};
|
|
108
161
|
});
|
|
109
162
|
}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Registers macros for use in Redpanda Connect contexts in the Redpanda documentation.
|
|
5
|
+
* @param {Registry} registry - The Antora registry where this block macro is registered.
|
|
6
|
+
* @param {Object} context - The Antora context that provides access to configuration data, such as parsed CSV content.
|
|
7
|
+
*/
|
|
3
8
|
module.exports.register = function (registry, context) {
|
|
4
9
|
function filterComponentTable() {
|
|
5
10
|
const nameInput = document.getElementById('componentTableSearch').value.trim().toLowerCase();
|
|
6
11
|
const typeFilter = Array.from(document.querySelector('#typeFilter').selectedOptions).map(option => option.value);
|
|
12
|
+
const cloudSupportInput= document.getElementById('cloudSupportFilter')?.value;
|
|
7
13
|
|
|
8
14
|
// Check for the existence of support and enterprise license filters (optional)
|
|
9
15
|
const supportFilterElement = document.querySelector('#supportFilter');
|
|
@@ -11,9 +17,9 @@ module.exports.register = function (registry, context) {
|
|
|
11
17
|
? Array.from(supportFilterElement.selectedOptions).map(option => option.value)
|
|
12
18
|
: [];
|
|
13
19
|
|
|
14
|
-
// Get the 'support=enterprise' query parameter from the URL
|
|
15
20
|
const params = getQueryParams();
|
|
16
21
|
const enterpriseSupportFilter = params.support === 'enterprise'; // Check if 'support=enterprise' is in the URL
|
|
22
|
+
const cloudSupportFilter = params.support === 'cloud'; // Check if 'support=cloud' is in the URL
|
|
17
23
|
|
|
18
24
|
const table = document.getElementById('componentTable');
|
|
19
25
|
const trs = table.getElementsByTagName('tr');
|
|
@@ -24,12 +30,14 @@ module.exports.register = function (registry, context) {
|
|
|
24
30
|
const typeTd = row.querySelector('td[id^="componentType-"]');
|
|
25
31
|
const supportTd = row.querySelector('td[id^="componentSupport-"]'); // Support column, if present
|
|
26
32
|
const enterpriseSupportTd = row.querySelector('td[id^="componentLicense-"]'); // Enterprise License column, if present
|
|
33
|
+
const cloudSupportTd = row.querySelector('td[id^="componentCloud-"]'); // Cloud support column, if present
|
|
27
34
|
|
|
28
35
|
if (typeTd) { // Ensure that at least the Type column is present
|
|
29
36
|
const nameText = nameTd ? nameTd.textContent.trim().toLowerCase() : '';
|
|
30
37
|
const typeText = typeTd.textContent.trim().toLowerCase().split(', ').map(item => item.trim());
|
|
31
38
|
const supportText = supportTd ? supportTd.textContent.trim().toLowerCase() : '';
|
|
32
39
|
const enterpriseSupportText = enterpriseSupportTd ? enterpriseSupportTd.textContent.trim().toLowerCase() : ''; // Yes or No
|
|
40
|
+
const cloudSupportText = cloudSupportTd ? cloudSupportTd.textContent.trim().toLowerCase() : ''; // Yes or No
|
|
33
41
|
|
|
34
42
|
// Determine if the row should be shown
|
|
35
43
|
const showRow =
|
|
@@ -37,6 +45,9 @@ module.exports.register = function (registry, context) {
|
|
|
37
45
|
(typeFilter.length === 0 || typeFilter.some(value => typeText.includes(value))) && // Filter by type
|
|
38
46
|
(!supportTd || supportFilter.length === 0 || supportFilter.some(value => supportText.includes(value))) && // Filter by support if present
|
|
39
47
|
(!enterpriseSupportFilter || !enterpriseSupportTd || supportText.includes('enterprise') || enterpriseSupportText === 'yes') // Filter by enterprise support if 'support=enterprise' is in the URL
|
|
48
|
+
&&
|
|
49
|
+
(!cloudSupportFilter || !cloudSupportTd || supportText.includes('cloud') || cloudSupportText === 'yes') && // Filter by cloud support if 'support=cloud' is in the URL
|
|
50
|
+
(!cloudSupportInput || cloudSupportText === cloudSupportInput)
|
|
40
51
|
);
|
|
41
52
|
|
|
42
53
|
row.style.display = showRow ? '' : 'none';
|
|
@@ -46,198 +57,468 @@ module.exports.register = function (registry, context) {
|
|
|
46
57
|
}
|
|
47
58
|
}
|
|
48
59
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Gets the first URL (either Redpanda Connect or Redpanda Cloud) for a given connector from the typesArray.
|
|
62
|
+
* If the cloud option is enabled (`isCloud = true`), it prefers the Redpanda Cloud URL; otherwise, it returns the Redpanda Connect URL.
|
|
63
|
+
*
|
|
64
|
+
* @param {Array} typesArray - An array of types where each type has a list of commercial names with URLs.
|
|
65
|
+
* @param {boolean} isCloud - A flag to indicate if Cloud URLs should be prioritized.
|
|
66
|
+
* @returns {string} - The first found URL (either Redpanda Connect or Cloud), or an empty string if no URL is available.
|
|
67
|
+
*/
|
|
68
|
+
function getFirstUrlFromTypesArray(typesArray, isCloud) {
|
|
69
|
+
for (const [type, commercialNames] of typesArray) {
|
|
70
|
+
for (const commercialName in commercialNames) {
|
|
71
|
+
const { urls = {} } = commercialNames[commercialName];
|
|
72
|
+
const redpandaConnectUrl = urls.redpandaConnectUrl || '';
|
|
73
|
+
const redpandaCloudUrl = urls.redpandaCloudUrl || '';
|
|
74
|
+
|
|
75
|
+
// Return Cloud URL if isCloud is true and Cloud URL exists
|
|
76
|
+
if (isCloud && redpandaCloudUrl) {
|
|
77
|
+
return redpandaCloudUrl;
|
|
64
78
|
}
|
|
65
|
-
connectors[connector].types.set(capitalize(type), { url });
|
|
66
79
|
|
|
67
|
-
//
|
|
68
|
-
if (
|
|
69
|
-
|
|
80
|
+
// Return Connect URL if isCloud is false or no Cloud URL exists
|
|
81
|
+
if (!isCloud && redpandaConnectUrl) {
|
|
82
|
+
return redpandaConnectUrl;
|
|
70
83
|
}
|
|
71
84
|
|
|
72
|
-
//
|
|
73
|
-
if (!
|
|
74
|
-
|
|
85
|
+
// If Cloud URL exists but isCloud is false, fallback to Cloud URL if no Connect URL exists
|
|
86
|
+
if (!isCloud && redpandaCloudUrl) {
|
|
87
|
+
return redpandaCloudUrl;
|
|
75
88
|
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return ''; // Return an empty string if no URL is found
|
|
92
|
+
}
|
|
76
93
|
|
|
77
|
-
|
|
78
|
-
commercial_name,
|
|
79
|
-
isCloudSupported
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
if (url) connectors[connector].urls.add(url);
|
|
94
|
+
const capitalize = s => s && s[0].toUpperCase() + s.slice(1);
|
|
83
95
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
96
|
+
/**
|
|
97
|
+
* Processes the parsed CSV data and returns a data structure organized by connector.
|
|
98
|
+
*
|
|
99
|
+
* This function processes each row in the CSV data to create a nested object where the key is the connector name.
|
|
100
|
+
* Each connector contains:
|
|
101
|
+
* - `types`: A Map of connector types, with associated URLs for Redpanda Connect and Redpanda Cloud.
|
|
102
|
+
* - Each type maps to commercial names and stores information on URLs, support level, and cloud support.
|
|
103
|
+
* - `supportLevels`: A Map of support levels containing commercial names and whether the type supports cloud.
|
|
104
|
+
* - `isLicensed`: A boolean flag indicating whether the connector requires an enterprise license.
|
|
105
|
+
* - `isCloudConnectorSupported`: A boolean flag indicating whether any type of this connector supports Redpanda Cloud.
|
|
106
|
+
*
|
|
107
|
+
* Expected structure of the returned data:
|
|
108
|
+
*
|
|
109
|
+
* {
|
|
110
|
+
* "connectorName": {
|
|
111
|
+
* "types": Map {
|
|
112
|
+
* "Input": { // Connector Type
|
|
113
|
+
* "commercial_name": {
|
|
114
|
+
* urls: {
|
|
115
|
+
* redpandaConnectUrl: "/redpanda-connect/components/inputs/connectorName/",
|
|
116
|
+
* redpandaCloudUrl: "/redpanda-cloud/develop/connect/components/inputs/connectorName/"
|
|
117
|
+
* },
|
|
118
|
+
* supportLevel: "certified", // Support level for this commercial name
|
|
119
|
+
* isCloudSupported: true // Whether this type supports cloud
|
|
120
|
+
* },
|
|
121
|
+
* ...
|
|
122
|
+
* },
|
|
123
|
+
* "Output": { // Another Connector Type
|
|
124
|
+
* "commercial_name": {
|
|
125
|
+
* urls: {
|
|
126
|
+
* redpandaConnectUrl: "/redpanda-connect/components/outputs/connectorName/",
|
|
127
|
+
* redpandaCloudUrl: "/redpanda-cloud/develop/connect/components/outputs/connectorName/"
|
|
128
|
+
* },
|
|
129
|
+
* supportLevel: "community", // Support level for this commercial name
|
|
130
|
+
* isCloudSupported: false // Whether this type supports cloud
|
|
131
|
+
* },
|
|
132
|
+
* ...
|
|
133
|
+
* },
|
|
134
|
+
* ...
|
|
135
|
+
* },
|
|
136
|
+
* "isLicensed": "Yes" or "No", // Indicates if the connector requires an Enterprise license.
|
|
137
|
+
* "isCloudConnectorSupported": true or false // Indicates if any type for this connector supports Redpanda Cloud.
|
|
138
|
+
* },
|
|
139
|
+
* ...
|
|
140
|
+
* }
|
|
141
|
+
*
|
|
142
|
+
* Notes:
|
|
143
|
+
* - For each connector, `types` is a `Map` that contains multiple connector types.
|
|
144
|
+
* - For each type, there may be multiple commercial names. Each commercial name contains URLs, support levels, and cloud support flags.
|
|
145
|
+
* - The `isCloudConnectorSupported` flag is set to `true` if any of the types for the connector support cloud.
|
|
146
|
+
*
|
|
147
|
+
* @param {object} parsedData - The CSV data parsed into an object.
|
|
148
|
+
* @returns {object} - The processed connectors data structure.
|
|
149
|
+
*/
|
|
150
|
+
function processConnectors(parsedData) {
|
|
151
|
+
return parsedData.data.reduce((connectors, row) => {
|
|
152
|
+
const { connector, commercial_name, type, support_level, is_cloud_supported, is_licensed, redpandaConnectUrl, redpandaCloudUrl } = row;
|
|
153
|
+
const isCloudSupported = is_cloud_supported === 'y';
|
|
154
|
+
|
|
155
|
+
// Initialize the connector if it's not already in the map
|
|
156
|
+
if (!connectors[connector]) {
|
|
157
|
+
connectors[connector] = {
|
|
158
|
+
types: new Map(),
|
|
159
|
+
isLicensed: is_licensed,
|
|
160
|
+
isCloudConnectorSupported: false
|
|
161
|
+
};
|
|
162
|
+
}
|
|
87
163
|
|
|
164
|
+
// Ensure type exists for the connector
|
|
165
|
+
if (!connectors[connector].types.has(type)) {
|
|
166
|
+
connectors[connector].types.set(type, {});
|
|
167
|
+
}
|
|
88
168
|
|
|
169
|
+
// Store the commercial name under the type
|
|
170
|
+
if (!connectors[connector].types.get(type)[commercial_name]) {
|
|
171
|
+
connectors[connector].types.get(type)[commercial_name] = {
|
|
172
|
+
urls: {
|
|
173
|
+
redpandaConnectUrl: redpandaConnectUrl || '',
|
|
174
|
+
redpandaCloudUrl: redpandaCloudUrl || ''
|
|
175
|
+
},
|
|
176
|
+
supportLevel: support_level,
|
|
177
|
+
isCloudSupported: isCloudSupported
|
|
178
|
+
};
|
|
179
|
+
}
|
|
89
180
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
181
|
+
// Check at the connector level if any commercial name supports cloud
|
|
182
|
+
if (isCloudSupported) {
|
|
183
|
+
connectors[connector].isCloudConnectorSupported = true;
|
|
184
|
+
}
|
|
94
185
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
})
|
|
99
|
-
.filter(item => item !== '');
|
|
186
|
+
return connectors;
|
|
187
|
+
}, {});
|
|
188
|
+
}
|
|
100
189
|
|
|
101
|
-
|
|
190
|
+
/**
|
|
191
|
+
* Processes parsed CSV data and groups SQL drivers by their support level.
|
|
192
|
+
*
|
|
193
|
+
* This function extracts the SQL drivers from the parsed CSV data, grouping
|
|
194
|
+
* them into two categories: "certified" and "community". Each driver is also
|
|
195
|
+
* associated with a flag indicating whether it supports cloud.
|
|
196
|
+
*
|
|
197
|
+
* @param {Object} parsedData - The parsed CSV data containing driver information.
|
|
198
|
+
* The expected structure of each row should contain at least the following:
|
|
199
|
+
* {
|
|
200
|
+
* connector: string, // The name of the connector
|
|
201
|
+
* commercial_name: string, // The commercial name of the SQL driver
|
|
202
|
+
* support_level: string, // The support level ('certified', 'community')
|
|
203
|
+
* is_cloud_supported: string // 'y' or 'n', indicating if the driver supports cloud
|
|
204
|
+
* }
|
|
205
|
+
*
|
|
206
|
+
* @returns {Object} - An object with two properties:
|
|
207
|
+
* - `certified`: An array of SQL drivers with 'certified' support level. Each driver contains:
|
|
208
|
+
* - `commercialName`: The trimmed commercial name of the driver (e.g., 'PostgreSQL').
|
|
209
|
+
* - `isCloudSupported`: A boolean indicating whether the driver supports cloud.
|
|
210
|
+
* - `community`: An array of SQL drivers with 'community' support level. Each driver contains:
|
|
211
|
+
* - `commercialName`: The trimmed commercial name of the driver (e.g., 'Trino').
|
|
212
|
+
* - `isCloudSupported`: A boolean indicating whether the driver supports cloud.
|
|
213
|
+
*
|
|
214
|
+
* Example return structure:
|
|
215
|
+
* {
|
|
216
|
+
* certified: [
|
|
217
|
+
* { commercialName: 'PostgreSQL', isCloudSupported: true },
|
|
218
|
+
* { commercialName: 'MySQL', isCloudSupported: true },
|
|
219
|
+
* ],
|
|
220
|
+
* community: [
|
|
221
|
+
* { commercialName: 'Trino', isCloudSupported: false },
|
|
222
|
+
* { commercialName: 'ClickHouse', isCloudSupported: false },
|
|
223
|
+
* ]
|
|
224
|
+
* }
|
|
225
|
+
*/
|
|
226
|
+
function processSqlDrivers(parsedData) {
|
|
227
|
+
const sqlDrivers = {
|
|
228
|
+
certified: [],
|
|
229
|
+
community: []
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
parsedData.data.forEach(row => {
|
|
233
|
+
const { connector: driverName, commercial_name, support_level, is_cloud_supported } = row;
|
|
234
|
+
const isCloudSupported = is_cloud_supported === 'y';
|
|
235
|
+
const supportLevel = support_level.toLowerCase();
|
|
236
|
+
|
|
237
|
+
// Only process SQL drivers
|
|
238
|
+
if (driverName.startsWith('sql_driver')) {
|
|
239
|
+
const driverData = {
|
|
240
|
+
commercialName: commercial_name.trim(),
|
|
241
|
+
isCloudSupported: isCloudSupported
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// Group drivers based on their support level
|
|
245
|
+
if (supportLevel === 'certified') {
|
|
246
|
+
sqlDrivers.certified.push(driverData);
|
|
247
|
+
} else if (supportLevel === 'community') {
|
|
248
|
+
sqlDrivers.community.push(driverData);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
});
|
|
102
252
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
.map(([level, commercialNames]) => {
|
|
106
|
-
let filteredNames = commercialNames;
|
|
253
|
+
return sqlDrivers;
|
|
254
|
+
}
|
|
107
255
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
256
|
+
/**
|
|
257
|
+
* Generates an HTML table for the list of connectors, including their types, support levels, and cloud support.
|
|
258
|
+
*
|
|
259
|
+
* This function iterates over the provided connectors and generates an HTML table row for each connector.
|
|
260
|
+
* It includes type-specific information, support level (including SQL driver details), licensing, and cloud support.
|
|
261
|
+
*
|
|
262
|
+
* @param {Object} connectors - An object containing the connector data, where each key is a connector name and
|
|
263
|
+
* each value contains details about its types, licensing, and cloud support.
|
|
264
|
+
* {
|
|
265
|
+
* types: Map - A map of connector types (e.g., Input, Output, Processor), with associated commercial names.
|
|
266
|
+
* isLicensed: 'Yes' or 'No' - Indicates if the connector requires an enterprise license.
|
|
267
|
+
* isCloudConnectorSupported: true or false - Indicates if any type for this connector supports Redpanda Cloud.
|
|
268
|
+
* }
|
|
269
|
+
* @param {Object} sqlDrivers - An object containing the SQL driver support data, separated by support level:
|
|
270
|
+
* {
|
|
271
|
+
* certified: Array<{ commercialName: string, isCloudSupported: boolean }>,
|
|
272
|
+
* community: Array<{ commercialName: string, isCloudSupported: boolean }>
|
|
273
|
+
* }
|
|
274
|
+
* @param {boolean} isCloud - A flag indicating whether to filter by cloud support. If true, only cloud-supported connectors are shown.
|
|
275
|
+
* @param {boolean} showAllInfo - A flag indicating whether to show all information or limit the data displayed (e.g., for cloud-only views).
|
|
276
|
+
*
|
|
277
|
+
* @returns {string} - A string containing the generated HTML for the connectors table rows.
|
|
278
|
+
* The output is a string of HTML rows with the following columns:
|
|
279
|
+
* - Connector name
|
|
280
|
+
* - Connector types (linked to Redpanda Connect or Cloud documentation URLs)
|
|
281
|
+
* - Support levels (including SQL drivers if applicable)
|
|
282
|
+
* - Enterprise licensing information
|
|
283
|
+
* - Cloud support status (Yes/No with a link if applicable)
|
|
284
|
+
*/
|
|
285
|
+
function generateConnectorsHTMLTable(connectors, sqlDrivers, isCloud, showAllInfo) {
|
|
286
|
+
return Object.entries(connectors)
|
|
287
|
+
.filter(([_, details]) => {
|
|
288
|
+
|
|
289
|
+
// If isCloud is true, filter out rows that do not support cloud
|
|
290
|
+
return !isCloud || details.isCloudConnectorSupported;
|
|
122
291
|
})
|
|
123
|
-
.
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
292
|
+
.map(([connector, details], id) => {
|
|
293
|
+
const { types, isCloudConnectorSupported, isLicensed } = details;
|
|
294
|
+
|
|
295
|
+
// Generate the type and commercial name links for each connector
|
|
296
|
+
const typesArray = Array.from(types.entries())
|
|
297
|
+
.map(([type, commercialNames]) => {
|
|
298
|
+
const uniqueCommercialNames = Object.keys(commercialNames);
|
|
299
|
+
const urlsArray = [];
|
|
300
|
+
uniqueCommercialNames.forEach(commercialName => {
|
|
301
|
+
const { urls = {}, isCloudSupported } = commercialNames[commercialName];
|
|
302
|
+
const redpandaConnectUrl = urls.redpandaConnectUrl || '';
|
|
303
|
+
const redpandaCloudUrl = urls.redpandaCloudUrl || '';
|
|
304
|
+
if (isCloud && !showAllInfo) {
|
|
305
|
+
// Only show Cloud URLs in the Cloud table
|
|
306
|
+
if (redpandaCloudUrl) {
|
|
307
|
+
urlsArray.push(`<a href="${redpandaCloudUrl}">${capitalize(type)}</a>`);
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
// Show Connect URLs in non-cloud tables
|
|
311
|
+
if (redpandaConnectUrl) {
|
|
312
|
+
urlsArray.push(`<a href="${redpandaConnectUrl}">${capitalize(type)}</a>`);
|
|
313
|
+
} else if (redpandaCloudUrl) {
|
|
314
|
+
// Fallback to Cloud URL if available
|
|
315
|
+
urlsArray.push(`<a href="${redpandaCloudUrl}">${capitalize(type)}</a>`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
// Filter out duplicates in URLs array for unique types
|
|
320
|
+
const uniqueUrls = [...new Set(urlsArray)];
|
|
321
|
+
return uniqueUrls.join(', '); // Return the types as a string of links
|
|
322
|
+
})
|
|
323
|
+
.filter(item => item !== '') // Remove any empty entries
|
|
324
|
+
.join(', '); // Join them into a single string
|
|
325
|
+
|
|
326
|
+
let supportLevelStr = ''; // Initialize the variable
|
|
327
|
+
// Generate the support level string
|
|
328
|
+
const supportLevels = Array.from(types.entries())
|
|
329
|
+
.reduce((supportLevelMap, [type, commercialNames]) => {
|
|
330
|
+
Object.entries(commercialNames).forEach(([commercialName, { supportLevel }]) => {
|
|
331
|
+
if (!supportLevelMap[supportLevel]) {
|
|
332
|
+
supportLevelMap[supportLevel] = {
|
|
333
|
+
types: new Set(),
|
|
334
|
+
commercialNames: new Map() // To track commercial names for each type
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
supportLevelMap[supportLevel].types.add(type); // Add the type to the Set (automatically removes duplicates)
|
|
338
|
+
|
|
339
|
+
// Add the commercial name to the type (only if it's not the connector name)
|
|
340
|
+
if (!supportLevelMap[supportLevel].commercialNames.has(type)) {
|
|
341
|
+
supportLevelMap[supportLevel].commercialNames.set(type, new Set());
|
|
342
|
+
}
|
|
343
|
+
if (commercialName.toLowerCase() !== connector.toLowerCase()) {
|
|
344
|
+
supportLevelMap[supportLevel].commercialNames.get(type).add(commercialName);
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
return supportLevelMap;
|
|
348
|
+
}, {});
|
|
349
|
+
|
|
350
|
+
// Generate the support level string
|
|
351
|
+
supportLevelStr = Object.entries(supportLevels)
|
|
352
|
+
.map(([supportLevel, { types, commercialNames }]) => {
|
|
353
|
+
const allCommercialNames = new Set(); // Store all commercial names for this support level
|
|
354
|
+
|
|
355
|
+
// Collect all commercial names across types
|
|
356
|
+
Array.from(commercialNames.entries()).forEach(([type, namesSet]) => {
|
|
357
|
+
namesSet.forEach(name => {
|
|
358
|
+
allCommercialNames.add(name);
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
// Case: Multiple support levels but no commercial names listed
|
|
363
|
+
if (Object.keys(supportLevels).length > 1 && allCommercialNames.size === 0 && types.size !== 0) {
|
|
364
|
+
const typesList = Array.from(types).join(', '); // Get all types
|
|
365
|
+
return `<p><b>${capitalize(supportLevel)}</b>: ${typesList}</p>`;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// If there's more than one commercial name, display them
|
|
369
|
+
if (allCommercialNames.size > 1) {
|
|
370
|
+
const allNamesArray = Array.from(allCommercialNames).join(', ');
|
|
371
|
+
return `<p><b>${capitalize(supportLevel)}</b>: ${allNamesArray}</p>`;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Otherwise, just show the support level
|
|
375
|
+
return `<p>${capitalize(supportLevel)}</p>`;
|
|
376
|
+
})
|
|
377
|
+
.join('');
|
|
378
|
+
|
|
379
|
+
// Add SQL driver support levels if the connector is a SQL connector.
|
|
380
|
+
// We assume only connectors starting with sql_ are relevant.
|
|
381
|
+
if (connector.startsWith('sql_')) {
|
|
382
|
+
const certifiedDrivers = sqlDrivers.certified.length ? `<strong>Certified:</strong> ${sqlDrivers.certified.map(driver => driver.commercialName).join(', ')}` : '';
|
|
383
|
+
const communityDrivers = sqlDrivers.community.length ? `<strong>Community:</strong> ${sqlDrivers.community.map(driver => driver.commercialName).join(', ')}` : '';
|
|
384
|
+
|
|
385
|
+
// Add the SQL driver support to the support level string
|
|
386
|
+
if (certifiedDrivers || communityDrivers) {
|
|
387
|
+
// Reset the support levels
|
|
388
|
+
supportLevelStr = ''
|
|
389
|
+
supportLevelStr += `<p>${certifiedDrivers}${certifiedDrivers && communityDrivers ? '</br> ' : ''}${communityDrivers}</p>`;
|
|
143
390
|
}
|
|
144
|
-
|
|
391
|
+
}
|
|
392
|
+
// Build the cloud support column
|
|
393
|
+
const firstCloudSupportedType = Array.from(types.entries())
|
|
394
|
+
.map(([_, commercialNames]) => Object.values(commercialNames).find(({ isCloudSupported }) => isCloudSupported))
|
|
395
|
+
.find(entry => entry && entry.urls.redpandaCloudUrl);
|
|
396
|
+
const cloudLinkDisplay = firstCloudSupportedType
|
|
397
|
+
? `<a href="${firstCloudSupportedType.urls.redpandaCloudUrl}">Yes</a>`
|
|
398
|
+
: 'No';
|
|
399
|
+
|
|
400
|
+
const firstUrl = getFirstUrlFromTypesArray(Array.from(types.entries()), isCloud);
|
|
401
|
+
|
|
402
|
+
// Logic for showAllInfo = true and isCloud = false
|
|
403
|
+
if (showAllInfo && !isCloud) {
|
|
145
404
|
return `
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
categories.forEach((category, index) => {
|
|
197
|
-
tabsHtml += `
|
|
198
|
-
<div id="${currentTabsId}-${category.name}--panel" class="tabpanel${index === 0 ? '' : ' is-hidden'}" aria-labelledby="${currentTabsId}-${category.name}"${index === 0 ? '' : ' hidden'} role="tabpanel">
|
|
199
|
-
<div class="listingblock">
|
|
200
|
-
<div class="content">
|
|
201
|
-
<p>${category.description}</p>
|
|
202
|
-
<div class="two-column-grid">`;
|
|
203
|
-
category.items.forEach(item => {
|
|
204
|
-
tabsHtml += `
|
|
205
|
-
<a href="${item.url}" class="component-card"><strong>${item.name}</strong></a>`;
|
|
206
|
-
});
|
|
207
|
-
tabsHtml += `
|
|
208
|
-
</div>
|
|
209
|
-
</div>
|
|
210
|
-
</div>
|
|
211
|
-
</div>`;
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
tabsHtml += `
|
|
215
|
-
</div>
|
|
216
|
-
</div>`;
|
|
217
|
-
|
|
218
|
-
return self.createBlock(parent, 'pass', tabsHtml);
|
|
219
|
-
});
|
|
220
|
-
});
|
|
405
|
+
<tr id="row-${id}">
|
|
406
|
+
<td class="tableblock halign-left valign-top" id="componentName-${id}">
|
|
407
|
+
<p class="tableblock"><a href="${firstUrl}"><code>${connector}</code></a></p>
|
|
408
|
+
</td>
|
|
409
|
+
<td class="tableblock halign-left valign-top" id="componentType-${id}">
|
|
410
|
+
<p class="tableblock">${typesArray}</p> <!-- Display types linked to Connect URL only -->
|
|
411
|
+
</td>
|
|
412
|
+
<td class="tableblock halign-left valign-top" id="componentSupport-${id}">
|
|
413
|
+
<p class="tableblock">${supportLevelStr.trim()}</p> <!-- Display support levels by type -->
|
|
414
|
+
</td>
|
|
415
|
+
<td class="tableblock halign-left valign-top" id="componentLicense-${id}">
|
|
416
|
+
<p class="tableblock">${isLicensed}</p>
|
|
417
|
+
</td>
|
|
418
|
+
<td class="tableblock halign-left valign-top" id="componentCloud-${id}">
|
|
419
|
+
<p class="tableblock">${cloudLinkDisplay}</p> <!-- Display 'Yes' or 'No' with link to first cloud-supported type -->
|
|
420
|
+
</td>
|
|
421
|
+
</tr>`;
|
|
422
|
+
}
|
|
423
|
+
// Logic for isCloud = true and showAllInfo = false (Cloud Table)
|
|
424
|
+
if (isCloud && !showAllInfo) {
|
|
425
|
+
return `
|
|
426
|
+
<tr id="row-${id}">
|
|
427
|
+
<td class="tableblock halign-left valign-top" id="componentName-${id}">
|
|
428
|
+
<p class="tableblock"><a href="${firstUrl}"><code>${connector}</code></a></p>
|
|
429
|
+
</td>
|
|
430
|
+
<td class="tableblock halign-left valign-top" id="componentType-${id}">
|
|
431
|
+
${typesArray} <!-- Display bulleted list for cloud types if commercial name differs -->
|
|
432
|
+
</td>
|
|
433
|
+
</tr>`;
|
|
434
|
+
}
|
|
435
|
+
// Default table display
|
|
436
|
+
return `
|
|
437
|
+
<tr id="row-${id}">
|
|
438
|
+
<td class="tableblock halign-left valign-top" id="componentName-${id}">
|
|
439
|
+
<p class="tableblock"><a href="${firstUrl}"><code>${connector}</code></a></p>
|
|
440
|
+
</td>
|
|
441
|
+
<td class="tableblock halign-left valign-top" id="componentType-${id}">
|
|
442
|
+
<p class="tableblock">${typesArray}</p> <!-- Display types without commercial names -->
|
|
443
|
+
</td>
|
|
444
|
+
<td class="tableblock halign-left valign-top" id="componentSupport-${id}">
|
|
445
|
+
<p class="tableblock">${supportLevelStr.trim()}</p>
|
|
446
|
+
</td>
|
|
447
|
+
<td class="tableblock halign-left valign-top" id="componentLicense-${id}">
|
|
448
|
+
<p class="tableblock">${isLicensed}</p>
|
|
449
|
+
</td>
|
|
450
|
+
</tr>`;
|
|
451
|
+
})
|
|
452
|
+
.filter(row => row !== '')
|
|
453
|
+
.join(''); // Filter out empty rows
|
|
454
|
+
}
|
|
221
455
|
|
|
222
|
-
|
|
456
|
+
/**
|
|
457
|
+
* Registers a block macro to generate a searchable and sortable table displaying connector data.
|
|
458
|
+
*
|
|
459
|
+
* This macro creates a dynamic HTML table that lists all available connectors, allowing filtering and sorting
|
|
460
|
+
* by type, support level, and cloud support.
|
|
461
|
+
*
|
|
462
|
+
*
|
|
463
|
+
* The table includes:
|
|
464
|
+
* - Name: The name of the connector.
|
|
465
|
+
* - Connector Type: The type of the connector.
|
|
466
|
+
* - Support Level: The support level for each connector, including associated SQL drivers if applicable.
|
|
467
|
+
* - Enterprise Licensed: Indicates whether the connector requires an Enterprise license.
|
|
468
|
+
* - Cloud Support: Shows if the connector is supported in Redpanda Cloud.
|
|
469
|
+
*
|
|
470
|
+
* Filters:
|
|
471
|
+
* - Type: Allows the user to filter by connector type.
|
|
472
|
+
* - Support: Allows the user to filter by support level (if not in cloud view).
|
|
473
|
+
* - Search: A text input field to search for connectors by name.
|
|
474
|
+
*
|
|
475
|
+
* Attributes:
|
|
476
|
+
* - `all`: If specified, displays additional columns such as support level, enterprise licensing, and cloud support.
|
|
477
|
+
*
|
|
478
|
+
* Data Sources:
|
|
479
|
+
* - `csvData`: Parsed CSV data that provides details about each connector.
|
|
480
|
+
* - SQL driver data is processed separately using the `processSqlDrivers` function, which groups the drivers by support level.
|
|
481
|
+
*
|
|
482
|
+
* Example usage in AsciiDoc:
|
|
483
|
+
* ```
|
|
484
|
+
* component_table::[]
|
|
485
|
+
* ```
|
|
486
|
+
*
|
|
487
|
+
* Example output:
|
|
488
|
+
* ```
|
|
489
|
+
* | Name | Connector Type | Support Level | Enterprise Licensed | Cloud Support |
|
|
490
|
+
* |-------|----------------|---------------- |---------------------|-----|
|
|
491
|
+
* | SQL | Input, Output | Certified | No | No |
|
|
492
|
+
* ```
|
|
493
|
+
*
|
|
494
|
+
* @param {Object} parent - The parent document where the table will be inserted.
|
|
495
|
+
* @param {string} target - Target element.
|
|
496
|
+
* @param {Object} attributes - Positional attributes passed to the macro.
|
|
497
|
+
* - `all`: If provided, extra columns are shown.
|
|
498
|
+
*/
|
|
223
499
|
registry.blockMacro(function () {
|
|
224
500
|
const self = this;
|
|
225
501
|
self.named('component_table');
|
|
226
|
-
self.
|
|
502
|
+
self.positionalAttributes(['all']); // Allows for displaying all data
|
|
503
|
+
self.process((parent, target, attributes) => {
|
|
227
504
|
const isCloud = parent.getDocument().getAttributes()['env-cloud'] !== undefined;
|
|
505
|
+
const showAllInfo = attributes?.all
|
|
506
|
+
|
|
228
507
|
const csvData = context.config?.attributes?.csvData || null;
|
|
229
508
|
if (!csvData) return console.error(`CSV data is not available for ${parent.getDocument().getAttributes()['page-relative-src-path']}. Make sure your playbook includes the generate-rp-connect-info extension.`)
|
|
509
|
+
|
|
510
|
+
const sqlDriversData = processSqlDrivers(csvData);
|
|
511
|
+
|
|
230
512
|
const types = new Set();
|
|
231
513
|
const uniqueSupportLevel = new Set();
|
|
232
|
-
|
|
233
514
|
csvData.data.forEach(row => {
|
|
234
|
-
if (row.type) types.add(row.type);
|
|
515
|
+
if (row.type && row.type.toLowerCase() !== 'sql_driver') types.add(row.type);
|
|
235
516
|
if (row.support_level) uniqueSupportLevel.add(row.support_level);
|
|
236
517
|
});
|
|
237
518
|
|
|
238
519
|
const createOptions = (values) =>
|
|
239
520
|
Array.from(values)
|
|
240
|
-
.map(value => `<option selected value="${value}">${capitalize(value).replace("_"," ")}</option>`)
|
|
521
|
+
.map(value => `<option selected value="${value}">${capitalize(value).replace("_", " ")}</option>`)
|
|
241
522
|
.join('');
|
|
242
523
|
|
|
243
524
|
let tableHtml = `
|
|
@@ -247,114 +528,167 @@ function generateConnectorsHTMLTable(connectors, isCloud) {
|
|
|
247
528
|
<select multiple class="type-dropdown" id="typeFilter" onchange="filterComponentTable()">
|
|
248
529
|
${createOptions(types)}
|
|
249
530
|
</select>
|
|
250
|
-
|
|
531
|
+
`;
|
|
532
|
+
|
|
251
533
|
if (!isCloud) {
|
|
252
534
|
tableHtml += `
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
535
|
+
<br><label for="supportFilter" id="labelForSupportFilter">Support:</label>
|
|
536
|
+
<select multiple class="type-dropdown" id="supportFilter" onchange="filterComponentTable()">
|
|
537
|
+
${createOptions(uniqueSupportLevel)}
|
|
538
|
+
</select>
|
|
539
|
+
`;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
if (showAllInfo) {
|
|
543
|
+
tableHtml += `
|
|
544
|
+
<br><label for="cloudSupportFilter">Available in Cloud:</label>
|
|
545
|
+
<select class="type-dropdown" id="cloudSupportFilter" onchange="filterComponentTable()">
|
|
546
|
+
<option value="">All</option>
|
|
547
|
+
<option value="yes">Yes</option>
|
|
548
|
+
<option value="no">No</option>
|
|
549
|
+
</select>
|
|
550
|
+
`;
|
|
257
551
|
}
|
|
258
552
|
|
|
259
553
|
tableHtml += `</div>
|
|
260
554
|
<table class="tableblock frame-all grid-all stripes-even no-clip stretch component-table sortable" id="componentTable">
|
|
261
555
|
<colgroup>
|
|
262
|
-
${
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
556
|
+
${showAllInfo
|
|
557
|
+
? '<col style="width: 20%;"><col style="width: 20%;"><col style="width: 20%;"><col style="width: 20%;"><col style="width: 20%;">'
|
|
558
|
+
: isCloud
|
|
559
|
+
? '<col style="width: 50%;"><col style="width: 50%;">'
|
|
560
|
+
: '<col style="width: 25%;"><col style="width: 25%;"><col style="width: 25%;"><col style="width: 25%;">'}
|
|
266
561
|
</colgroup>
|
|
267
562
|
<thead>
|
|
268
563
|
<tr>
|
|
269
564
|
<th class="tableblock halign-left valign-top">Name</th>
|
|
270
565
|
<th class="tableblock halign-left valign-top">Connector Type</th>
|
|
271
|
-
${
|
|
272
|
-
|
|
273
|
-
|
|
566
|
+
${showAllInfo ? `
|
|
567
|
+
<th class="tableblock halign-left valign-top">Support Level</th>
|
|
568
|
+
<th class="tableblock halign-left valign-top">Enterprise Licensed</th>
|
|
569
|
+
<th class="tableblock halign-left valign-top">Available in Cloud</th>
|
|
570
|
+
` : isCloud ? '' : `
|
|
571
|
+
<th class="tableblock halign-left valign-top">Support Level</th>
|
|
572
|
+
<th class="tableblock halign-left valign-top">Enterprise Licensed</th>`}
|
|
274
573
|
</tr>
|
|
275
574
|
</thead>
|
|
276
575
|
<tbody>
|
|
277
|
-
${generateConnectorsHTMLTable(processConnectors(csvData), isCloud)}
|
|
576
|
+
${generateConnectorsHTMLTable(processConnectors(csvData), sqlDriversData, isCloud, showAllInfo)}
|
|
278
577
|
</tbody>
|
|
279
578
|
</table>
|
|
280
579
|
<script>
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
return params;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
function updateComponentUrl(select, redirect) {
|
|
294
|
-
const anchor = select.closest('tr').querySelector('a');
|
|
295
|
-
anchor.href = select.value;
|
|
296
|
-
if (redirect) {
|
|
297
|
-
window.location.href = select.value; // Redirect to the new URL
|
|
580
|
+
${filterComponentTable.toString()}
|
|
581
|
+
function getQueryParams() {
|
|
582
|
+
const params = {};
|
|
583
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
584
|
+
searchParams.forEach((value, key) => {
|
|
585
|
+
params[key] = value.toLowerCase();
|
|
586
|
+
});
|
|
587
|
+
return params;
|
|
298
588
|
}
|
|
299
|
-
}
|
|
300
589
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
590
|
+
// Initialize Choices.js for type dropdowns
|
|
591
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
592
|
+
const params = getQueryParams();
|
|
593
|
+
const search = document.getElementById('componentTableSearch');
|
|
594
|
+
const typeFilter = document.getElementById('typeFilter');
|
|
595
|
+
const supportFilter = document.getElementById('supportFilter');
|
|
596
|
+
if (params.search && search) {
|
|
597
|
+
search.value = params.search;
|
|
598
|
+
}
|
|
599
|
+
if (params.type && typeFilter) {
|
|
600
|
+
typeFilter.value = params.type;
|
|
601
|
+
}
|
|
602
|
+
if (params.support && supportFilter) {
|
|
603
|
+
supportFilter.value = params.support;
|
|
604
|
+
}
|
|
605
|
+
filterComponentTable();
|
|
606
|
+
const typeDropdowns = document.querySelectorAll('.type-dropdown');
|
|
607
|
+
typeDropdowns.forEach(dropdown => {
|
|
608
|
+
new Choices(dropdown, {
|
|
609
|
+
searchEnabled: false,
|
|
610
|
+
allowHTML: true,
|
|
611
|
+
removeItemButton: true
|
|
612
|
+
});
|
|
613
|
+
});
|
|
323
614
|
});
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
615
|
+
</script>
|
|
616
|
+
`;
|
|
327
617
|
return self.createBlock(parent, 'pass', tableHtml);
|
|
328
618
|
});
|
|
329
619
|
});
|
|
330
620
|
|
|
621
|
+
/**
|
|
622
|
+
* Registers a block macro to generate a dropdown for component types and display metadata about the selected component.
|
|
623
|
+
*
|
|
624
|
+
* This macro creates a dropdown to select different types of a connector component, such as Input, Output, or Processor.
|
|
625
|
+
* It also provides links to the corresponding Cloud or Self-Managed documentation for the selected component type, and displays information on whether the connector requires an enterprise license.
|
|
626
|
+
*
|
|
627
|
+
*
|
|
628
|
+
* The dropdown lists all types of the connector component:
|
|
629
|
+
* - Type: A dropdown with options such as Input, Output, Processor, etc.
|
|
630
|
+
*
|
|
631
|
+
* Information displayed includes:
|
|
632
|
+
* - Availability: Displays links to Cloud and Self-Managed (Connect) documentation.
|
|
633
|
+
* - License: If the component requires an enterprise license, a message is displayed with a link to upgrade.
|
|
634
|
+
*
|
|
635
|
+
* Data Sources:
|
|
636
|
+
* - `csvData`: Parsed CSV data providing details about each connector.
|
|
637
|
+
* It filters the data to find the relevant rows for the current connector by matching the `doctitle`.
|
|
638
|
+
* - `redpandaConnectUrl`: URL for the Self-Managed version of the component documentation.
|
|
639
|
+
* - `redpandaCloudUrl`: URL for the Cloud version of the component documentation.
|
|
640
|
+
*
|
|
641
|
+
* Example usage in AsciiDoc:
|
|
642
|
+
* ```
|
|
643
|
+
* component_type_dropdown::[]
|
|
644
|
+
* ```
|
|
645
|
+
*
|
|
646
|
+
* Example output:
|
|
647
|
+
* ```
|
|
648
|
+
* <div class="metadata-block">
|
|
649
|
+
* <div style="padding:10px;display: flex;flex-direction: column;gap: 6px;">
|
|
650
|
+
* <p style="display: flex;align-items: center;gap: 6px;"><strong>Type:</strong>
|
|
651
|
+
* <select class="type-dropdown" onchange="window.location.href=this.value">
|
|
652
|
+
* <option value="..." data-support="certified">Input</option>
|
|
653
|
+
* <option value="..." data-support="community">Output</option>
|
|
654
|
+
* </select>
|
|
655
|
+
* </p>
|
|
656
|
+
* <p><strong>Available in:</strong> <a href="...">Cloud</a>, <a href="...">Self-Managed</a></p>
|
|
657
|
+
* <p><strong>License</strong>: This component requires an <a href="https://redpanda.com/compare-platform-editions" target="_blank">Enterprise license</a>. To upgrade, contact <a href="https://redpanda.com/try-redpanda?section=enterprise-trial" target="_blank" rel="noopener">Redpanda sales</a>.</p>
|
|
658
|
+
* </div>
|
|
659
|
+
* </div>
|
|
660
|
+
* ```
|
|
661
|
+
*
|
|
662
|
+
* @param {Object} parent - The parent document where the dropdown will be inserted.
|
|
663
|
+
* @param {string} target - The target element.
|
|
664
|
+
* @param {Object} attrs - Attributes passed to the macro.
|
|
665
|
+
*/
|
|
331
666
|
registry.blockMacro(function () {
|
|
332
667
|
const self = this;
|
|
333
668
|
self.named('component_type_dropdown');
|
|
334
669
|
self.process((parent, target, attrs) => {
|
|
335
670
|
const attributes = parent.getDocument().getAttributes();
|
|
671
|
+
const component = attributes['page-component-title']; // Current component (e.g., 'Redpanda Cloud' or 'Redpanda Connect')
|
|
336
672
|
const name = attributes['doctitle'];
|
|
337
673
|
const type = attributes['type'];
|
|
338
|
-
|
|
339
674
|
if (!name || !type) {
|
|
340
675
|
return self.createBlock(parent, 'pass', '');
|
|
341
676
|
}
|
|
342
|
-
|
|
343
677
|
const csvData = context.config?.attributes?.csvData || null;
|
|
344
|
-
if (!csvData) return console.error(`CSV data is not available for ${attributes['page-relative-src-path']}. Make sure your playbook includes the generate-rp-connect-info extension.`)
|
|
678
|
+
if (!csvData) return console.error(`CSV data is not available for ${attributes['page-relative-src-path']}. Make sure your playbook includes the generate-rp-connect-info extension.`);
|
|
679
|
+
// Filter for the specific connector by name
|
|
345
680
|
const componentRows = csvData.data.filter(row => row.connector.trim().toLowerCase() === name.trim().toLowerCase());
|
|
346
|
-
|
|
347
681
|
if (componentRows.length === 0) {
|
|
348
|
-
|
|
682
|
+
console.error(`No data found for connector: ${name}`);
|
|
349
683
|
}
|
|
350
|
-
|
|
351
|
-
// Process types from CSV
|
|
684
|
+
// Process types and metadata from CSV
|
|
352
685
|
const types = componentRows.map(row => ({
|
|
353
686
|
type: row.type.trim(),
|
|
354
687
|
support: row.support_level.trim(),
|
|
355
|
-
|
|
688
|
+
isCloudSupported: row.is_cloud_supported === 'y',
|
|
689
|
+
redpandaConnectUrl: row.redpandaConnectUrl,
|
|
690
|
+
redpandaCloudUrl: row.redpandaCloudUrl
|
|
356
691
|
}));
|
|
357
|
-
|
|
358
692
|
// Move the current page's type to the first position in the dropdown
|
|
359
693
|
const sortedTypes = [...types];
|
|
360
694
|
const currentTypeIndex = sortedTypes.findIndex(typeObj => typeObj.type === type);
|
|
@@ -362,50 +696,130 @@ function generateConnectorsHTMLTable(connectors, isCloud) {
|
|
|
362
696
|
const [currentType] = sortedTypes.splice(currentTypeIndex, 1);
|
|
363
697
|
sortedTypes.unshift(currentType);
|
|
364
698
|
}
|
|
365
|
-
|
|
366
699
|
// Check if the component requires an Enterprise license (based on support level)
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
<
|
|
372
|
-
<tbody>
|
|
373
|
-
<tr>
|
|
374
|
-
<td class="icon">
|
|
375
|
-
<i class="fa icon-note" title="Note"></i>
|
|
376
|
-
</td>
|
|
377
|
-
<td class="content">
|
|
378
|
-
<div class="paragraph">
|
|
379
|
-
<p>This feature requires an <a href="https://redpanda.com/compare-platform-editions" target="_blank">Enterprise license</a>. To upgrade, contact <a href="https://redpanda.com/try-redpanda?section=enterprise-trial" target="_blank" rel="noopener">Redpanda sales</a>.</p>
|
|
380
|
-
</div>
|
|
381
|
-
</td>
|
|
382
|
-
</tr>
|
|
383
|
-
</tbody>
|
|
384
|
-
</table>
|
|
385
|
-
</div>`;
|
|
700
|
+
const requiresEnterprise = componentRows.some(row => row.is_licensed.toLowerCase() === 'yes');
|
|
701
|
+
let enterpriseLicenseInfo = '';
|
|
702
|
+
if (requiresEnterprise) {
|
|
703
|
+
enterpriseLicenseInfo = `
|
|
704
|
+
<p><strong>License</strong>: This component requires an <a href="https://redpanda.com/compare-platform-editions" target="_blank">Enterprise license</a>. To upgrade, contact <a href="https://redpanda.com/try-redpanda?section=enterprise-trial" target="_blank" rel="noopener">Redpanda sales</a>.</p>`;
|
|
386
705
|
}
|
|
706
|
+
const isCloudSupported = componentRows.some(row => row.is_cloud_supported === 'y');
|
|
707
|
+
let availableInInfo = '';
|
|
708
|
+
|
|
709
|
+
if (isCloudSupported) {
|
|
710
|
+
const availableInLinks = [];
|
|
711
|
+
|
|
712
|
+
// Check if the component is Cloud and apply the `current-version` class
|
|
713
|
+
if (sortedTypes[0].redpandaCloudUrl) {
|
|
714
|
+
if (component === 'Cloud') {
|
|
715
|
+
availableInLinks.push('<span title="You are viewing the Cloud version of this component" class="current-version">Cloud</span>'); // Highlight the current version
|
|
716
|
+
} else {
|
|
717
|
+
availableInLinks.push(`<a title="View the Cloud version of this component" href="${sortedTypes[0].redpandaCloudUrl}">Cloud</a>`);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
387
720
|
|
|
388
|
-
|
|
721
|
+
// Check if the component is Connect and apply the `current-version` class
|
|
722
|
+
if (sortedTypes[0].redpandaConnectUrl) {
|
|
723
|
+
if (component === 'Connect') {
|
|
724
|
+
availableInLinks.push('<span title="You are viewing the Self-Managed version of this component" class="current-version">Self-Managed</span>'); // Highlight the current version
|
|
725
|
+
} else {
|
|
726
|
+
availableInLinks.push(`<a title="View the Self-Managed version of this component" href="${sortedTypes[0].redpandaConnectUrl}">Self-Managed</a>`);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
availableInInfo = `<p><strong>Available in:</strong> ${availableInLinks.join(', ')}</p>`;
|
|
730
|
+
} else {
|
|
731
|
+
availableInInfo = `<p><strong>Available in:</strong> <span title="You are viewing the Self-Managed version of this component" class="current-version">Self-Managed</span></p>`;
|
|
732
|
+
}
|
|
733
|
+
// Build the dropdown for types with links depending on the current component
|
|
389
734
|
let typeDropdown = '';
|
|
390
735
|
if (sortedTypes.length > 1) {
|
|
736
|
+
const dropdownLinks = sortedTypes.map(typeObj => {
|
|
737
|
+
const link = (component === 'Cloud' && typeObj.redpandaCloudUrl) || typeObj.redpandaConnectUrl;
|
|
738
|
+
return `<option value="${link}" data-support="${typeObj.support}">${capitalize(typeObj.type)}</option>`;
|
|
739
|
+
}).join('');
|
|
391
740
|
typeDropdown = `
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
</
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
741
|
+
<p style="display: flex;align-items: center;gap: 6px;"><strong>Type:</strong>
|
|
742
|
+
<select class="type-dropdown" onchange="window.location.href=this.value">
|
|
743
|
+
${dropdownLinks}
|
|
744
|
+
</select>
|
|
745
|
+
</p>
|
|
746
|
+
<script>
|
|
747
|
+
// Initialize Choices.js for type dropdowns
|
|
748
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
749
|
+
const typeDropdowns = document.querySelectorAll('.type-dropdown');
|
|
750
|
+
typeDropdowns.forEach(dropdown => {
|
|
751
|
+
new Choices(dropdown, { searchEnabled: false, allowHTML: true, shouldSort: false, itemSelectText: '' });
|
|
752
|
+
});
|
|
404
753
|
});
|
|
405
|
-
|
|
406
|
-
</script>`;
|
|
754
|
+
</script>`;
|
|
407
755
|
}
|
|
408
|
-
|
|
756
|
+
// Return the metadata block with consistent layout
|
|
757
|
+
return self.createBlock(parent, 'pass', `
|
|
758
|
+
<div class="metadata-block">
|
|
759
|
+
<div style="padding:10px;display: flex;flex-direction: column;gap: 6px;">
|
|
760
|
+
${typeDropdown}
|
|
761
|
+
${availableInInfo}
|
|
762
|
+
${enterpriseLicenseInfo}
|
|
763
|
+
</div>
|
|
764
|
+
</div>`);
|
|
765
|
+
});
|
|
766
|
+
});
|
|
767
|
+
|
|
768
|
+
let tabsCounter = 1; // Counter for generating unique IDs
|
|
769
|
+
|
|
770
|
+
// Add the category tabs for components
|
|
771
|
+
registry.blockMacro(function () {
|
|
772
|
+
const self = this;
|
|
773
|
+
self.named('components_by_category');
|
|
774
|
+
self.positionalAttributes(['type']);
|
|
775
|
+
self.process((parent, target, attrs) => {
|
|
776
|
+
const type = attrs.type;
|
|
777
|
+
const categoriesData = context.config?.attributes?.connectCategoriesData || null
|
|
778
|
+
if (!categoriesData) return console.error (`Category data is not available for ${parent.getDocument().getAttributes()['page-relative-src-path']}. Make sure your playbook includes the generate-rp-connect-categories extension.`)
|
|
779
|
+
const categories = categoriesData[type] || null;
|
|
780
|
+
const currentTabsId = `tabs-${tabsCounter++}`; // Unique ID for this set of tabs
|
|
781
|
+
if (!categories) return
|
|
782
|
+
|
|
783
|
+
let tabsHtml = `
|
|
784
|
+
<div id="${currentTabsId}" class="openblock tabs is-sync is-loaded" data-sync-group-id="${type}">
|
|
785
|
+
<div class="content">
|
|
786
|
+
<div class="ulist tablist">
|
|
787
|
+
<ul role="tablist">`;
|
|
788
|
+
|
|
789
|
+
categories.forEach((category, index) => {
|
|
790
|
+
tabsHtml += `
|
|
791
|
+
<li id="${currentTabsId}-${category.name}" class="tab" tabindex="${index === 0 ? '0' : '-1'}" role="tab" data-sync-id="${category.name}" aria-controls="${currentTabsId}-${category.name}--panel" aria-selected="${index === 0}">
|
|
792
|
+
<p>${category.name}</p>
|
|
793
|
+
</li>`;
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
tabsHtml += `
|
|
797
|
+
</ul>
|
|
798
|
+
</div>`;
|
|
799
|
+
|
|
800
|
+
categories.forEach((category, index) => {
|
|
801
|
+
tabsHtml += `
|
|
802
|
+
<div id="${currentTabsId}-${category.name}--panel" class="tabpanel${index === 0 ? '' : ' is-hidden'}" aria-labelledby="${currentTabsId}-${category.name}"${index === 0 ? '' : ' hidden'} role="tabpanel">
|
|
803
|
+
<div class="listingblock">
|
|
804
|
+
<div class="content">
|
|
805
|
+
<p>${category.description}</p>
|
|
806
|
+
<div class="two-column-grid">`;
|
|
807
|
+
category.items.forEach(item => {
|
|
808
|
+
tabsHtml += `
|
|
809
|
+
<a href="${item.url}" class="component-card"><strong>${item.name}</strong></a>`;
|
|
810
|
+
});
|
|
811
|
+
tabsHtml += `
|
|
812
|
+
</div>
|
|
813
|
+
</div>
|
|
814
|
+
</div>
|
|
815
|
+
</div>`;
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
tabsHtml += `
|
|
819
|
+
</div>
|
|
820
|
+
</div>`;
|
|
821
|
+
|
|
822
|
+
return self.createBlock(parent, 'pass', tabsHtml);
|
|
409
823
|
});
|
|
410
824
|
});
|
|
411
825
|
};
|