@squadbase/vite-server 0.1.17-dev.24af54e → 0.1.17-dev.7408ec4
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/dist/cli/index.js +1682 -425
- package/dist/connectors/airtable-oauth.js +22 -3
- package/dist/connectors/airtable.js +22 -3
- package/dist/connectors/amplitude.js +22 -3
- package/dist/connectors/asana.js +22 -3
- package/dist/connectors/attio.js +22 -3
- package/dist/connectors/aws-billing.js +22 -3
- package/dist/connectors/azure-sql.js +25 -6
- package/dist/connectors/backlog-api-key.js +22 -3
- package/dist/connectors/clickup.js +22 -3
- package/dist/connectors/cosmosdb.js +22 -3
- package/dist/connectors/customerio.js +23 -4
- package/dist/connectors/dbt.js +22 -3
- package/dist/connectors/freshdesk.js +22 -3
- package/dist/connectors/freshsales.js +22 -3
- package/dist/connectors/freshservice.js +22 -3
- package/dist/connectors/gamma.js +24 -5
- package/dist/connectors/github.js +22 -3
- package/dist/connectors/gmail-oauth.js +22 -3
- package/dist/connectors/gmail.js +22 -3
- package/dist/connectors/google-ads.js +22 -3
- package/dist/connectors/google-analytics-oauth.js +22 -3
- package/dist/connectors/google-analytics.js +222 -68
- package/dist/connectors/google-audit-log.js +22 -3
- package/dist/connectors/google-calendar-oauth.js +22 -3
- package/dist/connectors/google-calendar.js +22 -3
- package/dist/connectors/google-docs.js +22 -3
- package/dist/connectors/google-drive.js +22 -3
- package/dist/connectors/google-search-console-oauth.js +22 -3
- package/dist/connectors/google-sheets.js +22 -3
- package/dist/connectors/google-slides.js +22 -3
- package/dist/connectors/grafana.js +22 -3
- package/dist/connectors/hubspot-oauth.js +22 -3
- package/dist/connectors/hubspot.js +22 -3
- package/dist/connectors/influxdb.js +22 -3
- package/dist/connectors/intercom-oauth.js +22 -3
- package/dist/connectors/intercom.js +22 -3
- package/dist/connectors/jdbc.js +22 -3
- package/dist/connectors/jira-api-key.js +22 -3
- package/dist/connectors/kintone-api-token.js +22 -3
- package/dist/connectors/kintone.js +22 -3
- package/dist/connectors/linear.js +22 -3
- package/dist/connectors/linkedin-ads.js +22 -3
- package/dist/connectors/mailchimp-oauth.js +22 -3
- package/dist/connectors/mailchimp.js +22 -3
- package/dist/connectors/meta-ads-oauth.js +22 -3
- package/dist/connectors/meta-ads.js +22 -3
- package/dist/connectors/mixpanel.js +22 -3
- package/dist/connectors/monday.js +22 -3
- package/dist/connectors/mongodb.js +22 -3
- package/dist/connectors/notion-oauth.js +22 -3
- package/dist/connectors/notion.js +22 -3
- package/dist/connectors/oracle.js +48 -14
- package/dist/connectors/outlook-oauth.js +22 -3
- package/dist/connectors/powerbi-oauth.js +303 -37
- package/dist/connectors/salesforce.js +22 -3
- package/dist/connectors/semrush.js +360 -46
- package/dist/connectors/sentry.js +22 -3
- package/dist/connectors/shopify-oauth.js +22 -3
- package/dist/connectors/shopify.js +22 -3
- package/dist/connectors/sqlserver.js +25 -6
- package/dist/connectors/stripe-api-key.js +22 -3
- package/dist/connectors/stripe-oauth.js +22 -3
- package/dist/connectors/supabase.js +25 -6
- package/dist/connectors/tableau.js +240 -78
- package/dist/connectors/tiktok-ads.js +22 -3
- package/dist/connectors/wix-store.js +22 -3
- package/dist/connectors/zendesk-oauth.js +22 -3
- package/dist/connectors/zendesk.js +22 -3
- package/dist/index.js +1682 -425
- package/dist/main.js +1682 -425
- package/dist/vite-plugin.js +1682 -425
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -791,19 +791,28 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
791
791
|
};
|
|
792
792
|
let state = flow.initialState();
|
|
793
793
|
let answerIdx = 0;
|
|
794
|
+
const pendingParameterUpdates = [];
|
|
794
795
|
for (const step of flow.steps) {
|
|
795
796
|
const ans = ctx.answers[answerIdx];
|
|
796
797
|
if (ans && ans.questionSlug === step.slug) {
|
|
797
798
|
state = step.applyAnswer(state, ans.answer);
|
|
799
|
+
if (step.toParameterUpdates) {
|
|
800
|
+
pendingParameterUpdates.push(...step.toParameterUpdates(state));
|
|
801
|
+
}
|
|
798
802
|
answerIdx += 1;
|
|
799
803
|
continue;
|
|
800
804
|
}
|
|
805
|
+
const resolvedAllowFreeText = step.allowFreeText !== void 0 ? step.allowFreeText : true;
|
|
801
806
|
if (step.type === "text") {
|
|
802
807
|
return {
|
|
803
808
|
type: "nextQuestion",
|
|
804
809
|
questionSlug: step.slug,
|
|
805
810
|
question: step.question[ctx.language],
|
|
806
|
-
questionType: "text"
|
|
811
|
+
questionType: "text",
|
|
812
|
+
allowFreeText: resolvedAllowFreeText,
|
|
813
|
+
...pendingParameterUpdates.length > 0 && {
|
|
814
|
+
parameterUpdates: pendingParameterUpdates
|
|
815
|
+
}
|
|
807
816
|
};
|
|
808
817
|
}
|
|
809
818
|
const options = step.fetchOptions ? await step.fetchOptions(state, runtime) : [];
|
|
@@ -815,11 +824,21 @@ async function runSetupFlow(flow, params, ctx, config) {
|
|
|
815
824
|
questionSlug: step.slug,
|
|
816
825
|
question: step.question[ctx.language],
|
|
817
826
|
questionType: step.type,
|
|
818
|
-
options
|
|
827
|
+
options,
|
|
828
|
+
allowFreeText: resolvedAllowFreeText,
|
|
829
|
+
...pendingParameterUpdates.length > 0 && {
|
|
830
|
+
parameterUpdates: pendingParameterUpdates
|
|
831
|
+
}
|
|
819
832
|
};
|
|
820
833
|
}
|
|
821
834
|
const dataInvestigationResult = await flow.finalize(state, runtime);
|
|
822
|
-
return {
|
|
835
|
+
return {
|
|
836
|
+
type: "fulfilled",
|
|
837
|
+
dataInvestigationResult,
|
|
838
|
+
...pendingParameterUpdates.length > 0 && {
|
|
839
|
+
parameterUpdates: pendingParameterUpdates
|
|
840
|
+
}
|
|
841
|
+
};
|
|
823
842
|
}
|
|
824
843
|
async function resolveSetupSelection(params) {
|
|
825
844
|
const { selected, allSentinel, fetchAll, limit } = params;
|
|
@@ -998,7 +1017,46 @@ var INTERNAL_SCHEMAS = /* @__PURE__ */ new Set([
|
|
|
998
1017
|
"READER_ACCOUNT_USAGE",
|
|
999
1018
|
"DATA_SHARING_USAGE"
|
|
1000
1019
|
]);
|
|
1020
|
+
var OBJECT_TYPE_LABELS = {
|
|
1021
|
+
table: { ja: "\u30C6\u30FC\u30D6\u30EB", en: "Table" },
|
|
1022
|
+
view: { ja: "\u30D3\u30E5\u30FC", en: "View" },
|
|
1023
|
+
stream: { ja: "\u30B9\u30C8\u30EA\u30FC\u30E0", en: "Stream" },
|
|
1024
|
+
dynamic_table: { ja: "\u30C0\u30A4\u30CA\u30DF\u30C3\u30AF\u30C6\u30FC\u30D6\u30EB", en: "Dynamic Table" },
|
|
1025
|
+
pipe: { ja: "\u30D1\u30A4\u30D7", en: "Pipe" },
|
|
1026
|
+
task: { ja: "\u30BF\u30B9\u30AF", en: "Task" }
|
|
1027
|
+
};
|
|
1028
|
+
var HEADING_LABELS = {
|
|
1029
|
+
table: "Table",
|
|
1030
|
+
view: "View",
|
|
1031
|
+
stream: "Stream",
|
|
1032
|
+
dynamic_table: "Dynamic Table",
|
|
1033
|
+
pipe: "Pipe",
|
|
1034
|
+
task: "Task"
|
|
1035
|
+
};
|
|
1001
1036
|
function createSnowflakeSetupFlow(runQuery11) {
|
|
1037
|
+
const objectTypes = /* @__PURE__ */ new Map();
|
|
1038
|
+
async function fetchAllObjects(params, db, schema) {
|
|
1039
|
+
objectTypes.clear();
|
|
1040
|
+
const typeQueries = [
|
|
1041
|
+
["table", `SHOW TABLES IN SCHEMA "${db}"."${schema}"`],
|
|
1042
|
+
["view", `SHOW VIEWS IN SCHEMA "${db}"."${schema}"`],
|
|
1043
|
+
["stream", `SHOW STREAMS IN SCHEMA "${db}"."${schema}"`],
|
|
1044
|
+
["dynamic_table", `SHOW DYNAMIC TABLES IN SCHEMA "${db}"."${schema}"`],
|
|
1045
|
+
["pipe", `SHOW PIPES IN SCHEMA "${db}"."${schema}"`],
|
|
1046
|
+
["task", `SHOW TASKS IN SCHEMA "${db}"."${schema}"`]
|
|
1047
|
+
];
|
|
1048
|
+
const results = await Promise.all(
|
|
1049
|
+
typeQueries.map(([, sql]) => runQuery11(params, sql).catch(() => []))
|
|
1050
|
+
);
|
|
1051
|
+
for (let i = 0; i < results.length; i++) {
|
|
1052
|
+
const type = typeQueries[i][0];
|
|
1053
|
+
for (const r of results[i]) {
|
|
1054
|
+
const name = String(r["name"] ?? "");
|
|
1055
|
+
if (name) objectTypes.set(name, type);
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
return Array.from(objectTypes.keys());
|
|
1059
|
+
}
|
|
1002
1060
|
return {
|
|
1003
1061
|
initialState: () => ({}),
|
|
1004
1062
|
steps: [
|
|
@@ -1038,22 +1096,27 @@ function createSnowflakeSetupFlow(runQuery11) {
|
|
|
1038
1096
|
slug: "tables",
|
|
1039
1097
|
type: "multiSelect",
|
|
1040
1098
|
question: {
|
|
1041
|
-
ja: "\u5BFE\u8C61\
|
|
1042
|
-
en: "Select target tables
|
|
1099
|
+
ja: "\u5BFE\u8C61\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u30FB\u30B9\u30C8\u30EA\u30FC\u30E0\u7B49\u3001\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
1100
|
+
en: "Select target objects (tables, views, streams, etc. \u2014 multi-select allowed)"
|
|
1043
1101
|
},
|
|
1044
1102
|
async fetchOptions(state, rt) {
|
|
1045
1103
|
if (!state.database || !state.schema) return [];
|
|
1046
|
-
const
|
|
1104
|
+
const allNames = await fetchAllObjects(
|
|
1047
1105
|
rt.params,
|
|
1048
|
-
|
|
1106
|
+
state.database,
|
|
1107
|
+
state.schema
|
|
1049
1108
|
);
|
|
1050
|
-
const
|
|
1109
|
+
const options = allNames.map((name) => {
|
|
1110
|
+
const type = objectTypes.get(name) ?? "table";
|
|
1111
|
+
const typeLabel = OBJECT_TYPE_LABELS[type][rt.language];
|
|
1112
|
+
return { value: name, label: `${name} (${typeLabel})` };
|
|
1113
|
+
});
|
|
1051
1114
|
return [
|
|
1052
1115
|
{
|
|
1053
1116
|
value: ALL_TABLES,
|
|
1054
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\
|
|
1117
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8" : "All objects"
|
|
1055
1118
|
},
|
|
1056
|
-
...
|
|
1119
|
+
...options
|
|
1057
1120
|
];
|
|
1058
1121
|
},
|
|
1059
1122
|
applyAnswer: (state, answer) => ({ ...state, tables: answer })
|
|
@@ -1065,16 +1128,10 @@ function createSnowflakeSetupFlow(runQuery11) {
|
|
|
1065
1128
|
}
|
|
1066
1129
|
const db = state.database;
|
|
1067
1130
|
const schema = state.schema;
|
|
1068
|
-
const
|
|
1131
|
+
const targetObjects = await resolveSetupSelection({
|
|
1069
1132
|
selected: state.tables,
|
|
1070
1133
|
allSentinel: ALL_TABLES,
|
|
1071
|
-
fetchAll:
|
|
1072
|
-
const rows = await runQuery11(
|
|
1073
|
-
rt.params,
|
|
1074
|
-
`SHOW TABLES IN SCHEMA "${db}"."${schema}"`
|
|
1075
|
-
);
|
|
1076
|
-
return rows.map((r) => String(r["name"] ?? "")).filter((name) => name);
|
|
1077
|
-
},
|
|
1134
|
+
fetchAll: () => fetchAllObjects(rt.params, db, schema),
|
|
1078
1135
|
limit: SNOWFLAKE_SETUP_MAX_TABLES
|
|
1079
1136
|
});
|
|
1080
1137
|
const sections = [
|
|
@@ -1085,24 +1142,66 @@ function createSnowflakeSetupFlow(runQuery11) {
|
|
|
1085
1142
|
`#### Schema: ${schema}`,
|
|
1086
1143
|
""
|
|
1087
1144
|
];
|
|
1088
|
-
for (const
|
|
1089
|
-
const
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1145
|
+
for (const name of targetObjects) {
|
|
1146
|
+
const type = objectTypes.get(name) ?? "table";
|
|
1147
|
+
const heading = HEADING_LABELS[type];
|
|
1148
|
+
switch (type) {
|
|
1149
|
+
case "table":
|
|
1150
|
+
case "view":
|
|
1151
|
+
case "dynamic_table":
|
|
1152
|
+
case "stream": {
|
|
1153
|
+
const cols = await runQuery11(
|
|
1154
|
+
rt.params,
|
|
1155
|
+
`DESCRIBE TABLE "${db}"."${schema}"."${name}"`
|
|
1156
|
+
).catch(() => []);
|
|
1157
|
+
sections.push(`##### ${heading}: ${name}`, "");
|
|
1158
|
+
if (cols.length > 0) {
|
|
1159
|
+
sections.push("| Column | Type | Nullable | Default |");
|
|
1160
|
+
sections.push("|--------|------|----------|---------|");
|
|
1161
|
+
for (const c of cols) {
|
|
1162
|
+
const colName = String(c["name"] ?? "");
|
|
1163
|
+
const colType = String(c["type"] ?? "");
|
|
1164
|
+
const nullable = String(c["null?"] ?? "");
|
|
1165
|
+
const defaultValue = c["default"] == null ? "-" : String(c["default"]);
|
|
1166
|
+
sections.push(
|
|
1167
|
+
`| ${colName} | ${colType} | ${nullable} | ${defaultValue} |`
|
|
1168
|
+
);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
sections.push("");
|
|
1172
|
+
break;
|
|
1173
|
+
}
|
|
1174
|
+
case "pipe": {
|
|
1175
|
+
const rows = await runQuery11(
|
|
1176
|
+
rt.params,
|
|
1177
|
+
`SHOW PIPES LIKE '${name.replace(/'/g, "''")}' IN SCHEMA "${db}"."${schema}"`
|
|
1178
|
+
).catch(() => []);
|
|
1179
|
+
sections.push(`##### Pipe: ${name}`, "");
|
|
1180
|
+
if (rows.length > 0) {
|
|
1181
|
+
const definition = String(rows[0]["definition"] ?? "-");
|
|
1182
|
+
sections.push(`Definition: \`${definition}\``, "");
|
|
1183
|
+
}
|
|
1184
|
+
sections.push("");
|
|
1185
|
+
break;
|
|
1186
|
+
}
|
|
1187
|
+
case "task": {
|
|
1188
|
+
const rows = await runQuery11(
|
|
1189
|
+
rt.params,
|
|
1190
|
+
`SHOW TASKS LIKE '${name.replace(/'/g, "''")}' IN SCHEMA "${db}"."${schema}"`
|
|
1191
|
+
).catch(() => []);
|
|
1192
|
+
sections.push(`##### Task: ${name}`, "");
|
|
1193
|
+
if (rows.length > 0) {
|
|
1194
|
+
const schedule = String(rows[0]["schedule"] ?? "-");
|
|
1195
|
+
const taskState = String(rows[0]["state"] ?? "-");
|
|
1196
|
+
const definition = String(rows[0]["definition"] ?? "-");
|
|
1197
|
+
sections.push(`Schedule: ${schedule}`, "");
|
|
1198
|
+
sections.push(`State: ${taskState}`, "");
|
|
1199
|
+
sections.push(`Definition: \`${definition}\``, "");
|
|
1200
|
+
}
|
|
1201
|
+
sections.push("");
|
|
1202
|
+
break;
|
|
1203
|
+
}
|
|
1104
1204
|
}
|
|
1105
|
-
sections.push("");
|
|
1106
1205
|
}
|
|
1107
1206
|
return sections.join("\n");
|
|
1108
1207
|
}
|
|
@@ -1915,8 +2014,8 @@ var postgresqlSetupFlow = {
|
|
|
1915
2014
|
slug: "tables",
|
|
1916
2015
|
type: "multiSelect",
|
|
1917
2016
|
question: {
|
|
1918
|
-
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
1919
|
-
en: "Select target tables (multi-select allowed)"
|
|
2017
|
+
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
2018
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
1920
2019
|
},
|
|
1921
2020
|
async fetchOptions(state, rt) {
|
|
1922
2021
|
if (!state.schema) return [];
|
|
@@ -1925,7 +2024,7 @@ var postgresqlSetupFlow = {
|
|
|
1925
2024
|
return [
|
|
1926
2025
|
{
|
|
1927
2026
|
value: ALL_TABLES2,
|
|
1928
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
2027
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
1929
2028
|
},
|
|
1930
2029
|
...tableOptions
|
|
1931
2030
|
];
|
|
@@ -2262,8 +2361,8 @@ var mysqlSetupFlow = {
|
|
|
2262
2361
|
slug: "tables",
|
|
2263
2362
|
type: "multiSelect",
|
|
2264
2363
|
question: {
|
|
2265
|
-
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
2266
|
-
en: "Select target tables (multi-select allowed)"
|
|
2364
|
+
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
2365
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
2267
2366
|
},
|
|
2268
2367
|
async fetchOptions(state, rt) {
|
|
2269
2368
|
if (!state.database) return [];
|
|
@@ -2272,7 +2371,7 @@ var mysqlSetupFlow = {
|
|
|
2272
2371
|
return [
|
|
2273
2372
|
{
|
|
2274
2373
|
value: ALL_TABLES3,
|
|
2275
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
2374
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
2276
2375
|
},
|
|
2277
2376
|
...tableOptions
|
|
2278
2377
|
];
|
|
@@ -2723,6 +2822,72 @@ var bigqueryOnboarding = new ConnectorOnboarding({
|
|
|
2723
2822
|
}
|
|
2724
2823
|
});
|
|
2725
2824
|
|
|
2825
|
+
// ../connectors/src/table-grouping.ts
|
|
2826
|
+
var SHARD_GROUP_PREFIX = "__SHARD__";
|
|
2827
|
+
var DEFAULT_MIN_SHARD_GROUP_SIZE = 3;
|
|
2828
|
+
function extractDateShardSuffix(name) {
|
|
2829
|
+
const m = name.match(/^(.+)_(\d{8})$/);
|
|
2830
|
+
if (!m) return null;
|
|
2831
|
+
const [, prefix, suffix] = m;
|
|
2832
|
+
const y = +suffix.slice(0, 4);
|
|
2833
|
+
const mo = +suffix.slice(4, 6);
|
|
2834
|
+
const d = +suffix.slice(6, 8);
|
|
2835
|
+
if (y < 2e3 || y > 2099 || mo < 1 || mo > 12 || d < 1 || d > 31) {
|
|
2836
|
+
return null;
|
|
2837
|
+
}
|
|
2838
|
+
return { prefix, suffix };
|
|
2839
|
+
}
|
|
2840
|
+
function detectDateShardCandidates(tableNames, minCount = DEFAULT_MIN_SHARD_GROUP_SIZE) {
|
|
2841
|
+
const prefixMap = /* @__PURE__ */ new Map();
|
|
2842
|
+
const nonSharded = [];
|
|
2843
|
+
for (const name of tableNames) {
|
|
2844
|
+
const parsed = extractDateShardSuffix(name);
|
|
2845
|
+
if (parsed) {
|
|
2846
|
+
const existing = prefixMap.get(parsed.prefix);
|
|
2847
|
+
if (existing) {
|
|
2848
|
+
existing.push(name);
|
|
2849
|
+
} else {
|
|
2850
|
+
prefixMap.set(parsed.prefix, [name]);
|
|
2851
|
+
}
|
|
2852
|
+
} else {
|
|
2853
|
+
nonSharded.push(name);
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2856
|
+
const candidates = [];
|
|
2857
|
+
const singles = [...nonSharded];
|
|
2858
|
+
for (const [prefix, members] of prefixMap) {
|
|
2859
|
+
if (members.length >= minCount) {
|
|
2860
|
+
candidates.push({ prefix, count: members.length, members });
|
|
2861
|
+
} else {
|
|
2862
|
+
singles.push(...members);
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2865
|
+
return { singles, candidates };
|
|
2866
|
+
}
|
|
2867
|
+
function schemasMatch(columnsA, columnsB) {
|
|
2868
|
+
if (columnsA.length !== columnsB.length) return false;
|
|
2869
|
+
return columnsA.every(
|
|
2870
|
+
(a, i) => String(a["column_name"] ?? "") === String(columnsB[i]["column_name"] ?? "") && String(a["data_type"] ?? "") === String(columnsB[i]["data_type"] ?? "")
|
|
2871
|
+
);
|
|
2872
|
+
}
|
|
2873
|
+
function isShardGroupValue(value) {
|
|
2874
|
+
return value.startsWith(SHARD_GROUP_PREFIX);
|
|
2875
|
+
}
|
|
2876
|
+
function getShardGroupPrefix(value) {
|
|
2877
|
+
return value.slice(SHARD_GROUP_PREFIX.length);
|
|
2878
|
+
}
|
|
2879
|
+
function shardGroupValue(prefix) {
|
|
2880
|
+
return `${SHARD_GROUP_PREFIX}${prefix}`;
|
|
2881
|
+
}
|
|
2882
|
+
function buildGroupedTableOptions(singles, confirmedGroups, language) {
|
|
2883
|
+
const groupOptions = confirmedGroups.sort((a, b) => a.prefix.localeCompare(b.prefix)).map((g) => ({
|
|
2884
|
+
value: shardGroupValue(g.prefix),
|
|
2885
|
+
label: language === "ja" ? `${g.prefix}_* (\u65E5\u4ED8\u30B7\u30E3\u30FC\u30C9: ${g.count} \u30C6\u30FC\u30D6\u30EB)` : `${g.prefix}_* (date-sharded: ${g.count} tables)`
|
|
2886
|
+
}));
|
|
2887
|
+
const singleOptions = singles.sort().map((name) => ({ value: name }));
|
|
2888
|
+
return [...groupOptions, ...singleOptions];
|
|
2889
|
+
}
|
|
2890
|
+
|
|
2726
2891
|
// ../connectors/src/connectors/bigquery/utils.ts
|
|
2727
2892
|
async function runQuery5(params, sql) {
|
|
2728
2893
|
const { BigQuery } = await import("@google-cloud/bigquery");
|
|
@@ -2753,13 +2918,23 @@ async function listProjects(params) {
|
|
|
2753
2918
|
scopes: ["https://www.googleapis.com/auth/bigquery"]
|
|
2754
2919
|
});
|
|
2755
2920
|
const client = await auth.getClient();
|
|
2756
|
-
const
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2921
|
+
const projects = [];
|
|
2922
|
+
let pageToken;
|
|
2923
|
+
do {
|
|
2924
|
+
const url = pageToken ? `https://bigquery.googleapis.com/bigquery/v2/projects?pageToken=${encodeURIComponent(pageToken)}` : "https://bigquery.googleapis.com/bigquery/v2/projects";
|
|
2925
|
+
const res = await client.request({ url });
|
|
2926
|
+
for (const p of res.data.projects ?? []) {
|
|
2927
|
+
const id = p.projectReference?.projectId ?? "";
|
|
2928
|
+
if (id) {
|
|
2929
|
+
projects.push({
|
|
2930
|
+
projectId: id,
|
|
2931
|
+
friendlyName: p.friendlyName ?? id
|
|
2932
|
+
});
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
pageToken = res.data.nextPageToken;
|
|
2936
|
+
} while (pageToken);
|
|
2937
|
+
return projects;
|
|
2763
2938
|
}
|
|
2764
2939
|
async function listDatasets(params, projectId2) {
|
|
2765
2940
|
const { BigQuery } = await import("@google-cloud/bigquery");
|
|
@@ -2797,23 +2972,25 @@ var PUBLIC_DATASETS = [
|
|
|
2797
2972
|
labelEn: "bigquery-public-data.austin_311 (public dataset / customer service requests)"
|
|
2798
2973
|
}
|
|
2799
2974
|
];
|
|
2975
|
+
var SAME_AS_BILLING = "__SAME_AS_BILLING__";
|
|
2800
2976
|
function resolveDatasetRef(state) {
|
|
2801
2977
|
const dataset = state.dataset ?? "";
|
|
2802
2978
|
if (dataset.includes(".")) {
|
|
2803
2979
|
const [datasetProject, ...rest] = dataset.split(".");
|
|
2804
2980
|
return { datasetProject, datasetId: rest.join(".") };
|
|
2805
2981
|
}
|
|
2806
|
-
return { datasetProject: state.
|
|
2982
|
+
return { datasetProject: state.databaseProject ?? "", datasetId: dataset };
|
|
2807
2983
|
}
|
|
2808
2984
|
var bigquerySetupFlow = {
|
|
2809
2985
|
initialState: () => ({}),
|
|
2810
2986
|
steps: [
|
|
2811
2987
|
{
|
|
2812
|
-
slug: "
|
|
2988
|
+
slug: "billingProject",
|
|
2813
2989
|
type: "select",
|
|
2990
|
+
allowFreeText: false,
|
|
2814
2991
|
question: {
|
|
2815
|
-
ja: "\
|
|
2816
|
-
en: "Select the
|
|
2992
|
+
ja: "BigQuery \u3092\u5B9F\u884C\u3059\u308B Google Cloud \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08BigQuery \u306E\u8AB2\u91D1\u306B\u7D10\u3065\u304F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3067\u3059\uFF09",
|
|
2993
|
+
en: "Select the Google Cloud project to run BigQuery queries (this project will be billed for BigQuery usage)"
|
|
2817
2994
|
},
|
|
2818
2995
|
async fetchOptions(_state, rt) {
|
|
2819
2996
|
const projects = await listProjects(rt.params);
|
|
@@ -2822,7 +2999,40 @@ var bigquerySetupFlow = {
|
|
|
2822
2999
|
label: p.friendlyName && p.friendlyName !== p.projectId ? `${p.friendlyName} (${p.projectId})` : p.projectId
|
|
2823
3000
|
}));
|
|
2824
3001
|
},
|
|
2825
|
-
applyAnswer: (state, answer) => ({
|
|
3002
|
+
applyAnswer: (state, answer) => ({
|
|
3003
|
+
...state,
|
|
3004
|
+
billingProject: answer[0]
|
|
3005
|
+
}),
|
|
3006
|
+
toParameterUpdates: (state) => state.billingProject ? [{ slug: "project-id", value: state.billingProject }] : []
|
|
3007
|
+
},
|
|
3008
|
+
{
|
|
3009
|
+
slug: "databaseProject",
|
|
3010
|
+
type: "select",
|
|
3011
|
+
question: {
|
|
3012
|
+
ja: "\u30C7\u30FC\u30BF\u304C\u683C\u7D0D\u3055\u308C\u3066\u3044\u308B GCP \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044",
|
|
3013
|
+
en: "Select the GCP project where your data resides"
|
|
3014
|
+
},
|
|
3015
|
+
async fetchOptions(state, rt) {
|
|
3016
|
+
if (!state.billingProject) return [];
|
|
3017
|
+
const sameAsBillingOption = {
|
|
3018
|
+
value: SAME_AS_BILLING,
|
|
3019
|
+
label: rt.language === "ja" ? `\u8AB2\u91D1\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3068\u540C\u3058 (${state.billingProject})` : `Same as billing project (${state.billingProject})`
|
|
3020
|
+
};
|
|
3021
|
+
const projects = await listProjects(rt.params);
|
|
3022
|
+
const projectOptions = projects.filter((p) => p.projectId !== state.billingProject).map((p) => ({
|
|
3023
|
+
value: p.projectId,
|
|
3024
|
+
label: p.friendlyName && p.friendlyName !== p.projectId ? `${p.friendlyName} (${p.projectId})` : p.projectId
|
|
3025
|
+
}));
|
|
3026
|
+
const publicProjectOption = {
|
|
3027
|
+
value: "bigquery-public-data",
|
|
3028
|
+
label: rt.language === "ja" ? "bigquery-public-data (Google \u30D1\u30D6\u30EA\u30C3\u30AF\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8)" : "bigquery-public-data (Google public datasets)"
|
|
3029
|
+
};
|
|
3030
|
+
return [sameAsBillingOption, ...projectOptions, publicProjectOption];
|
|
3031
|
+
},
|
|
3032
|
+
applyAnswer: (state, answer) => ({
|
|
3033
|
+
...state,
|
|
3034
|
+
databaseProject: answer[0] === SAME_AS_BILLING ? state.billingProject : answer[0]
|
|
3035
|
+
})
|
|
2826
3036
|
},
|
|
2827
3037
|
{
|
|
2828
3038
|
slug: "dataset",
|
|
@@ -2832,8 +3042,8 @@ var bigquerySetupFlow = {
|
|
|
2832
3042
|
en: "Select the dataset to use for setup"
|
|
2833
3043
|
},
|
|
2834
3044
|
async fetchOptions(state, rt) {
|
|
2835
|
-
if (!state.
|
|
2836
|
-
const datasets = await listDatasets(rt.params, state.
|
|
3045
|
+
if (!state.databaseProject) return [];
|
|
3046
|
+
const datasets = await listDatasets(rt.params, state.databaseProject);
|
|
2837
3047
|
const projectDatasetOptions = datasets.map((d) => ({
|
|
2838
3048
|
value: d.datasetId,
|
|
2839
3049
|
label: d.location ? `${d.datasetId} (${d.location})` : d.datasetId
|
|
@@ -2850,66 +3060,140 @@ var bigquerySetupFlow = {
|
|
|
2850
3060
|
slug: "tables",
|
|
2851
3061
|
type: "multiSelect",
|
|
2852
3062
|
question: {
|
|
2853
|
-
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
2854
|
-
en: "Select target tables (multi-select allowed)"
|
|
3063
|
+
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
3064
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
2855
3065
|
},
|
|
2856
3066
|
async fetchOptions(state, rt) {
|
|
2857
|
-
if (!state.
|
|
3067
|
+
if (!state.billingProject || !state.dataset) return [];
|
|
2858
3068
|
const { datasetProject, datasetId } = resolveDatasetRef(state);
|
|
2859
3069
|
const rows = await runQuery5(
|
|
2860
3070
|
rt.params,
|
|
2861
3071
|
`SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
|
|
2862
3072
|
);
|
|
2863
|
-
const
|
|
3073
|
+
const tableNames = rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
|
|
3074
|
+
const { singles, candidates } = detectDateShardCandidates(tableNames);
|
|
3075
|
+
const confirmedGroups = [];
|
|
3076
|
+
const rejectedSingles = [];
|
|
3077
|
+
for (const candidate of candidates) {
|
|
3078
|
+
const [first, second] = candidate.members;
|
|
3079
|
+
const colRows = await runQuery5(
|
|
3080
|
+
rt.params,
|
|
3081
|
+
`SELECT table_name, column_name, data_type FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name IN ('${first.replaceAll("'", "''")}', '${second.replaceAll("'", "''")}') ORDER BY table_name, ordinal_position`
|
|
3082
|
+
);
|
|
3083
|
+
const colsA = colRows.filter(
|
|
3084
|
+
(r) => String(r["table_name"]) === first
|
|
3085
|
+
);
|
|
3086
|
+
const colsB = colRows.filter(
|
|
3087
|
+
(r) => String(r["table_name"]) === second
|
|
3088
|
+
);
|
|
3089
|
+
if (schemasMatch(colsA, colsB)) {
|
|
3090
|
+
confirmedGroups.push(candidate);
|
|
3091
|
+
} else {
|
|
3092
|
+
rejectedSingles.push(...candidate.members);
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
3095
|
+
const allSingles = [...singles, ...rejectedSingles];
|
|
2864
3096
|
return [
|
|
2865
3097
|
{
|
|
2866
3098
|
value: ALL_TABLES4,
|
|
2867
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
3099
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
2868
3100
|
},
|
|
2869
|
-
...
|
|
3101
|
+
...buildGroupedTableOptions(allSingles, confirmedGroups, rt.language)
|
|
2870
3102
|
];
|
|
2871
3103
|
},
|
|
2872
3104
|
applyAnswer: (state, answer) => ({ ...state, tables: answer })
|
|
2873
3105
|
}
|
|
2874
3106
|
],
|
|
2875
3107
|
async finalize(state, rt) {
|
|
2876
|
-
if (!state.
|
|
3108
|
+
if (!state.billingProject || !state.databaseProject || !state.dataset || !state.tables) {
|
|
2877
3109
|
throw new Error("BigQuery setup: incomplete state on finalize");
|
|
2878
3110
|
}
|
|
2879
3111
|
const { datasetProject, datasetId } = resolveDatasetRef(state);
|
|
2880
|
-
const
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
3112
|
+
const fetchAllTableNames = async () => {
|
|
3113
|
+
const rows = await runQuery5(
|
|
3114
|
+
rt.params,
|
|
3115
|
+
`SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
|
|
3116
|
+
);
|
|
3117
|
+
return rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
|
|
3118
|
+
};
|
|
3119
|
+
let entries;
|
|
3120
|
+
if (state.tables.includes(ALL_TABLES4)) {
|
|
3121
|
+
const allNames = await fetchAllTableNames();
|
|
3122
|
+
const { singles, candidates } = detectDateShardCandidates(allNames);
|
|
3123
|
+
entries = [
|
|
3124
|
+
...candidates.map(
|
|
3125
|
+
(g) => ({
|
|
3126
|
+
type: "shardGroup",
|
|
3127
|
+
prefix: g.prefix,
|
|
3128
|
+
count: g.count,
|
|
3129
|
+
representative: g.members[0]
|
|
3130
|
+
})
|
|
3131
|
+
),
|
|
3132
|
+
...singles.map((name) => ({ type: "table", name }))
|
|
3133
|
+
];
|
|
3134
|
+
} else {
|
|
3135
|
+
const shardSelections = state.tables.filter(isShardGroupValue);
|
|
3136
|
+
const tableSelections = state.tables.filter(
|
|
3137
|
+
(v) => !isShardGroupValue(v)
|
|
3138
|
+
);
|
|
3139
|
+
entries = tableSelections.map(
|
|
3140
|
+
(name) => ({ type: "table", name })
|
|
3141
|
+
);
|
|
3142
|
+
if (shardSelections.length > 0) {
|
|
3143
|
+
const allNames = await fetchAllTableNames();
|
|
3144
|
+
for (const value of shardSelections) {
|
|
3145
|
+
const prefix = getShardGroupPrefix(value);
|
|
3146
|
+
const members = allNames.filter((n) => {
|
|
3147
|
+
const parsed = extractDateShardSuffix(n);
|
|
3148
|
+
return parsed != null && parsed.prefix === prefix;
|
|
3149
|
+
});
|
|
3150
|
+
if (members.length > 0) {
|
|
3151
|
+
entries.push({
|
|
3152
|
+
type: "shardGroup",
|
|
3153
|
+
prefix,
|
|
3154
|
+
count: members.length,
|
|
3155
|
+
representative: members[0]
|
|
3156
|
+
});
|
|
3157
|
+
}
|
|
3158
|
+
}
|
|
3159
|
+
}
|
|
3160
|
+
}
|
|
3161
|
+
entries = entries.slice(0, BIGQUERY_SETUP_MAX_TABLES);
|
|
3162
|
+
const queryColumns = async (tableName) => runQuery5(
|
|
3163
|
+
rt.params,
|
|
3164
|
+
`SELECT column_name, data_type, is_nullable FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name = '${tableName.replaceAll("'", "''")}' ORDER BY ordinal_position`
|
|
3165
|
+
);
|
|
2892
3166
|
const sections = [
|
|
2893
3167
|
"## BigQuery",
|
|
2894
3168
|
"",
|
|
2895
|
-
`### Billing project: ${state.
|
|
3169
|
+
`### Billing project: ${state.billingProject}`,
|
|
3170
|
+
"",
|
|
3171
|
+
`### Database project: ${state.databaseProject}`,
|
|
2896
3172
|
"",
|
|
2897
3173
|
`#### Dataset: ${datasetProject}.${datasetId}`,
|
|
2898
3174
|
""
|
|
2899
3175
|
];
|
|
2900
|
-
for (const
|
|
2901
|
-
const
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
3176
|
+
for (const entry of entries) {
|
|
3177
|
+
const tableName = entry.type === "shardGroup" ? entry.representative : entry.name;
|
|
3178
|
+
const cols = await queryColumns(tableName);
|
|
3179
|
+
if (entry.type === "shardGroup") {
|
|
3180
|
+
sections.push(
|
|
3181
|
+
`##### Table: ${entry.prefix}_* (date-sharded, ${entry.count} tables)`,
|
|
3182
|
+
""
|
|
3183
|
+
);
|
|
3184
|
+
sections.push(
|
|
3185
|
+
`_Query all shards: \`SELECT * FROM \`${datasetProject}.${datasetId}.${entry.prefix}_*\` WHERE _TABLE_SUFFIX BETWEEN 'YYYYMMDD' AND 'YYYYMMDD'\`_`,
|
|
3186
|
+
""
|
|
3187
|
+
);
|
|
3188
|
+
} else {
|
|
3189
|
+
sections.push(`##### Table: ${entry.name}`, "");
|
|
3190
|
+
}
|
|
2906
3191
|
sections.push("| Column | Type | Nullable |");
|
|
2907
3192
|
sections.push("|--------|------|----------|");
|
|
2908
3193
|
for (const c of cols) {
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
sections.push(`| ${name} | ${type} | ${nullable} |`);
|
|
3194
|
+
sections.push(
|
|
3195
|
+
`| ${String(c["column_name"] ?? "")} | ${String(c["data_type"] ?? "")} | ${String(c["is_nullable"] ?? "")} |`
|
|
3196
|
+
);
|
|
2913
3197
|
}
|
|
2914
3198
|
sections.push("");
|
|
2915
3199
|
}
|
|
@@ -3407,21 +3691,30 @@ async function runQuery6(proxyFetch, projectId2, sql) {
|
|
|
3407
3691
|
return parseQueryResponse(data);
|
|
3408
3692
|
}
|
|
3409
3693
|
async function listProjects2(proxyFetch) {
|
|
3410
|
-
const
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3694
|
+
const projects = [];
|
|
3695
|
+
let pageToken;
|
|
3696
|
+
do {
|
|
3697
|
+
const url = pageToken ? `https://bigquery.googleapis.com/bigquery/v2/projects?pageToken=${encodeURIComponent(pageToken)}` : "https://bigquery.googleapis.com/bigquery/v2/projects";
|
|
3698
|
+
const res = await proxyFetch(url, { method: "GET" });
|
|
3699
|
+
if (!res.ok) {
|
|
3700
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
3701
|
+
throw new Error(
|
|
3702
|
+
`BigQuery listProjects failed: HTTP ${res.status} ${errorText}`
|
|
3703
|
+
);
|
|
3704
|
+
}
|
|
3705
|
+
const data = await res.json();
|
|
3706
|
+
for (const p of data.projects ?? []) {
|
|
3707
|
+
const id = p.projectReference?.projectId ?? "";
|
|
3708
|
+
if (id) {
|
|
3709
|
+
projects.push({
|
|
3710
|
+
projectId: id,
|
|
3711
|
+
friendlyName: p.friendlyName ?? id
|
|
3712
|
+
});
|
|
3713
|
+
}
|
|
3714
|
+
}
|
|
3715
|
+
pageToken = data.nextPageToken;
|
|
3716
|
+
} while (pageToken);
|
|
3717
|
+
return projects;
|
|
3425
3718
|
}
|
|
3426
3719
|
async function listDatasets2(proxyFetch, projectId2) {
|
|
3427
3720
|
const res = await proxyFetch(
|
|
@@ -3461,23 +3754,25 @@ var PUBLIC_DATASETS2 = [
|
|
|
3461
3754
|
labelEn: "bigquery-public-data.austin_311 (public dataset / customer service requests)"
|
|
3462
3755
|
}
|
|
3463
3756
|
];
|
|
3757
|
+
var SAME_AS_BILLING2 = "__SAME_AS_BILLING__";
|
|
3464
3758
|
function resolveDatasetRef2(state) {
|
|
3465
3759
|
const dataset = state.dataset ?? "";
|
|
3466
3760
|
if (dataset.includes(".")) {
|
|
3467
3761
|
const [datasetProject, ...rest] = dataset.split(".");
|
|
3468
3762
|
return { datasetProject, datasetId: rest.join(".") };
|
|
3469
3763
|
}
|
|
3470
|
-
return { datasetProject: state.
|
|
3764
|
+
return { datasetProject: state.databaseProject ?? "", datasetId: dataset };
|
|
3471
3765
|
}
|
|
3472
3766
|
var bigqueryOauthSetupFlow = {
|
|
3473
3767
|
initialState: () => ({}),
|
|
3474
3768
|
steps: [
|
|
3475
3769
|
{
|
|
3476
|
-
slug: "
|
|
3770
|
+
slug: "billingProject",
|
|
3477
3771
|
type: "select",
|
|
3772
|
+
allowFreeText: false,
|
|
3478
3773
|
question: {
|
|
3479
|
-
ja: "\
|
|
3480
|
-
en: "Select the
|
|
3774
|
+
ja: "BigQuery \u3092\u5B9F\u884C\u3059\u308B Google Cloud \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08BigQuery \u306E\u8AB2\u91D1\u306B\u7D10\u3065\u304F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3067\u3059\uFF09",
|
|
3775
|
+
en: "Select the Google Cloud project to run BigQuery queries (this project will be billed for BigQuery usage)"
|
|
3481
3776
|
},
|
|
3482
3777
|
async fetchOptions(_state, rt) {
|
|
3483
3778
|
const projects = await listProjects2(rt.config.proxyFetch);
|
|
@@ -3486,7 +3781,40 @@ var bigqueryOauthSetupFlow = {
|
|
|
3486
3781
|
label: p.friendlyName && p.friendlyName !== p.projectId ? `${p.friendlyName} (${p.projectId})` : p.projectId
|
|
3487
3782
|
}));
|
|
3488
3783
|
},
|
|
3489
|
-
applyAnswer: (state, answer) => ({
|
|
3784
|
+
applyAnswer: (state, answer) => ({
|
|
3785
|
+
...state,
|
|
3786
|
+
billingProject: answer[0]
|
|
3787
|
+
}),
|
|
3788
|
+
toParameterUpdates: (state) => state.billingProject ? [{ slug: "project-id", value: state.billingProject }] : []
|
|
3789
|
+
},
|
|
3790
|
+
{
|
|
3791
|
+
slug: "databaseProject",
|
|
3792
|
+
type: "select",
|
|
3793
|
+
question: {
|
|
3794
|
+
ja: "\u30C7\u30FC\u30BF\u304C\u683C\u7D0D\u3055\u308C\u3066\u3044\u308B GCP \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044",
|
|
3795
|
+
en: "Select the GCP project where your data resides"
|
|
3796
|
+
},
|
|
3797
|
+
async fetchOptions(state, rt) {
|
|
3798
|
+
if (!state.billingProject) return [];
|
|
3799
|
+
const sameAsBillingOption = {
|
|
3800
|
+
value: SAME_AS_BILLING2,
|
|
3801
|
+
label: rt.language === "ja" ? `\u8AB2\u91D1\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3068\u540C\u3058 (${state.billingProject})` : `Same as billing project (${state.billingProject})`
|
|
3802
|
+
};
|
|
3803
|
+
const projects = await listProjects2(rt.config.proxyFetch);
|
|
3804
|
+
const projectOptions = projects.filter((p) => p.projectId !== state.billingProject).map((p) => ({
|
|
3805
|
+
value: p.projectId,
|
|
3806
|
+
label: p.friendlyName && p.friendlyName !== p.projectId ? `${p.friendlyName} (${p.projectId})` : p.projectId
|
|
3807
|
+
}));
|
|
3808
|
+
const publicProjectOption = {
|
|
3809
|
+
value: "bigquery-public-data",
|
|
3810
|
+
label: rt.language === "ja" ? "bigquery-public-data (Google \u30D1\u30D6\u30EA\u30C3\u30AF\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8)" : "bigquery-public-data (Google public datasets)"
|
|
3811
|
+
};
|
|
3812
|
+
return [sameAsBillingOption, ...projectOptions, publicProjectOption];
|
|
3813
|
+
},
|
|
3814
|
+
applyAnswer: (state, answer) => ({
|
|
3815
|
+
...state,
|
|
3816
|
+
databaseProject: answer[0] === SAME_AS_BILLING2 ? state.billingProject : answer[0]
|
|
3817
|
+
})
|
|
3490
3818
|
},
|
|
3491
3819
|
{
|
|
3492
3820
|
slug: "dataset",
|
|
@@ -3496,8 +3824,11 @@ var bigqueryOauthSetupFlow = {
|
|
|
3496
3824
|
en: "Select the dataset to use for setup"
|
|
3497
3825
|
},
|
|
3498
3826
|
async fetchOptions(state, rt) {
|
|
3499
|
-
if (!state.
|
|
3500
|
-
const datasets = await listDatasets2(
|
|
3827
|
+
if (!state.databaseProject) return [];
|
|
3828
|
+
const datasets = await listDatasets2(
|
|
3829
|
+
rt.config.proxyFetch,
|
|
3830
|
+
state.databaseProject
|
|
3831
|
+
);
|
|
3501
3832
|
const projectDatasetOptions = datasets.map((d) => ({
|
|
3502
3833
|
value: d.datasetId,
|
|
3503
3834
|
label: d.location ? `${d.datasetId} (${d.location})` : d.datasetId
|
|
@@ -3514,70 +3845,145 @@ var bigqueryOauthSetupFlow = {
|
|
|
3514
3845
|
slug: "tables",
|
|
3515
3846
|
type: "multiSelect",
|
|
3516
3847
|
question: {
|
|
3517
|
-
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
3518
|
-
en: "Select target tables (multi-select allowed)"
|
|
3848
|
+
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
3849
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
3519
3850
|
},
|
|
3520
3851
|
async fetchOptions(state, rt) {
|
|
3521
|
-
if (!state.
|
|
3852
|
+
if (!state.billingProject || !state.dataset) return [];
|
|
3522
3853
|
const { datasetProject, datasetId } = resolveDatasetRef2(state);
|
|
3523
3854
|
const rows = await runQuery6(
|
|
3524
3855
|
rt.config.proxyFetch,
|
|
3525
|
-
state.
|
|
3856
|
+
state.billingProject,
|
|
3526
3857
|
`SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
|
|
3527
3858
|
);
|
|
3528
|
-
const
|
|
3859
|
+
const tableNames = rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
|
|
3860
|
+
const { singles, candidates } = detectDateShardCandidates(tableNames);
|
|
3861
|
+
const confirmedGroups = [];
|
|
3862
|
+
const rejectedSingles = [];
|
|
3863
|
+
for (const candidate of candidates) {
|
|
3864
|
+
const [first, second] = candidate.members;
|
|
3865
|
+
const colRows = await runQuery6(
|
|
3866
|
+
rt.config.proxyFetch,
|
|
3867
|
+
state.billingProject,
|
|
3868
|
+
`SELECT table_name, column_name, data_type FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name IN ('${first.replaceAll("'", "''")}', '${second.replaceAll("'", "''")}') ORDER BY table_name, ordinal_position`
|
|
3869
|
+
);
|
|
3870
|
+
const colsA = colRows.filter(
|
|
3871
|
+
(r) => String(r["table_name"]) === first
|
|
3872
|
+
);
|
|
3873
|
+
const colsB = colRows.filter(
|
|
3874
|
+
(r) => String(r["table_name"]) === second
|
|
3875
|
+
);
|
|
3876
|
+
if (schemasMatch(colsA, colsB)) {
|
|
3877
|
+
confirmedGroups.push(candidate);
|
|
3878
|
+
} else {
|
|
3879
|
+
rejectedSingles.push(...candidate.members);
|
|
3880
|
+
}
|
|
3881
|
+
}
|
|
3882
|
+
const allSingles = [...singles, ...rejectedSingles];
|
|
3529
3883
|
return [
|
|
3530
3884
|
{
|
|
3531
3885
|
value: ALL_TABLES5,
|
|
3532
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
3886
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
3533
3887
|
},
|
|
3534
|
-
...
|
|
3888
|
+
...buildGroupedTableOptions(allSingles, confirmedGroups, rt.language)
|
|
3535
3889
|
];
|
|
3536
3890
|
},
|
|
3537
3891
|
applyAnswer: (state, answer) => ({ ...state, tables: answer })
|
|
3538
3892
|
}
|
|
3539
3893
|
],
|
|
3540
3894
|
async finalize(state, rt) {
|
|
3541
|
-
if (!state.
|
|
3895
|
+
if (!state.billingProject || !state.databaseProject || !state.dataset || !state.tables) {
|
|
3542
3896
|
throw new Error("BigQuery OAuth setup: incomplete state on finalize");
|
|
3543
3897
|
}
|
|
3544
|
-
const billingProject = state.
|
|
3898
|
+
const billingProject = state.billingProject;
|
|
3545
3899
|
const { datasetProject, datasetId } = resolveDatasetRef2(state);
|
|
3546
|
-
const
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3900
|
+
const fetchAllTableNames = async () => {
|
|
3901
|
+
const rows = await runQuery6(
|
|
3902
|
+
rt.config.proxyFetch,
|
|
3903
|
+
billingProject,
|
|
3904
|
+
`SELECT table_name FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.TABLES`
|
|
3905
|
+
);
|
|
3906
|
+
return rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
|
|
3907
|
+
};
|
|
3908
|
+
let entries;
|
|
3909
|
+
if (state.tables.includes(ALL_TABLES5)) {
|
|
3910
|
+
const allNames = await fetchAllTableNames();
|
|
3911
|
+
const { singles, candidates } = detectDateShardCandidates(allNames);
|
|
3912
|
+
entries = [
|
|
3913
|
+
...candidates.map(
|
|
3914
|
+
(g) => ({
|
|
3915
|
+
type: "shardGroup",
|
|
3916
|
+
prefix: g.prefix,
|
|
3917
|
+
count: g.count,
|
|
3918
|
+
representative: g.members[0]
|
|
3919
|
+
})
|
|
3920
|
+
),
|
|
3921
|
+
...singles.map((name) => ({ type: "table", name }))
|
|
3922
|
+
];
|
|
3923
|
+
} else {
|
|
3924
|
+
const shardSelections = state.tables.filter(isShardGroupValue);
|
|
3925
|
+
const tableSelections = state.tables.filter(
|
|
3926
|
+
(v) => !isShardGroupValue(v)
|
|
3927
|
+
);
|
|
3928
|
+
entries = tableSelections.map(
|
|
3929
|
+
(name) => ({ type: "table", name })
|
|
3930
|
+
);
|
|
3931
|
+
if (shardSelections.length > 0) {
|
|
3932
|
+
const allNames = await fetchAllTableNames();
|
|
3933
|
+
for (const value of shardSelections) {
|
|
3934
|
+
const prefix = getShardGroupPrefix(value);
|
|
3935
|
+
const members = allNames.filter((n) => {
|
|
3936
|
+
const parsed = extractDateShardSuffix(n);
|
|
3937
|
+
return parsed != null && parsed.prefix === prefix;
|
|
3938
|
+
});
|
|
3939
|
+
if (members.length > 0) {
|
|
3940
|
+
entries.push({
|
|
3941
|
+
type: "shardGroup",
|
|
3942
|
+
prefix,
|
|
3943
|
+
count: members.length,
|
|
3944
|
+
representative: members[0]
|
|
3945
|
+
});
|
|
3946
|
+
}
|
|
3947
|
+
}
|
|
3948
|
+
}
|
|
3949
|
+
}
|
|
3950
|
+
entries = entries.slice(0, BIGQUERY_OAUTH_SETUP_MAX_TABLES);
|
|
3951
|
+
const queryColumns = async (tableName) => runQuery6(
|
|
3952
|
+
rt.config.proxyFetch,
|
|
3953
|
+
billingProject,
|
|
3954
|
+
`SELECT column_name, data_type, is_nullable FROM \`${datasetProject}.${datasetId}\`.INFORMATION_SCHEMA.COLUMNS WHERE table_name = '${tableName.replaceAll("'", "''")}' ORDER BY ordinal_position`
|
|
3955
|
+
);
|
|
3559
3956
|
const sections = [
|
|
3560
3957
|
"## BigQuery (OAuth)",
|
|
3561
3958
|
"",
|
|
3562
3959
|
`### Billing project: ${billingProject}`,
|
|
3563
3960
|
"",
|
|
3961
|
+
`### Database project: ${state.databaseProject}`,
|
|
3962
|
+
"",
|
|
3564
3963
|
`#### Dataset: ${datasetProject}.${datasetId}`,
|
|
3565
3964
|
""
|
|
3566
3965
|
];
|
|
3567
|
-
for (const
|
|
3568
|
-
const
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3966
|
+
for (const entry of entries) {
|
|
3967
|
+
const tableName = entry.type === "shardGroup" ? entry.representative : entry.name;
|
|
3968
|
+
const cols = await queryColumns(tableName);
|
|
3969
|
+
if (entry.type === "shardGroup") {
|
|
3970
|
+
sections.push(
|
|
3971
|
+
`##### Table: ${entry.prefix}_* (date-sharded, ${entry.count} tables)`,
|
|
3972
|
+
""
|
|
3973
|
+
);
|
|
3974
|
+
sections.push(
|
|
3975
|
+
`_Query all shards: \`SELECT * FROM \`${datasetProject}.${datasetId}.${entry.prefix}_*\` WHERE _TABLE_SUFFIX BETWEEN 'YYYYMMDD' AND 'YYYYMMDD'\`_`,
|
|
3976
|
+
""
|
|
3977
|
+
);
|
|
3978
|
+
} else {
|
|
3979
|
+
sections.push(`##### Table: ${entry.name}`, "");
|
|
3980
|
+
}
|
|
3574
3981
|
sections.push("| Column | Type | Nullable |");
|
|
3575
3982
|
sections.push("|--------|------|----------|");
|
|
3576
3983
|
for (const c of cols) {
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
sections.push(`| ${name} | ${type} | ${nullable} |`);
|
|
3984
|
+
sections.push(
|
|
3985
|
+
`| ${String(c["column_name"] ?? "")} | ${String(c["data_type"] ?? "")} | ${String(c["is_nullable"] ?? "")} |`
|
|
3986
|
+
);
|
|
3581
3987
|
}
|
|
3582
3988
|
sections.push("");
|
|
3583
3989
|
}
|
|
@@ -5286,14 +5692,15 @@ function isInternalSchema2(name) {
|
|
|
5286
5692
|
function quoteLiteral(value) {
|
|
5287
5693
|
return "'" + value.replace(/'/g, "''") + "'";
|
|
5288
5694
|
}
|
|
5289
|
-
async function
|
|
5695
|
+
async function fetchTableAndViewNames(params, schema) {
|
|
5290
5696
|
const rows = await runQuery7(
|
|
5291
5697
|
params,
|
|
5292
|
-
`SELECT
|
|
5293
|
-
WHERE
|
|
5294
|
-
|
|
5698
|
+
`SELECT table_name FROM information_schema.tables
|
|
5699
|
+
WHERE table_schema = ${quoteLiteral(schema)}
|
|
5700
|
+
AND table_type IN ('BASE TABLE', 'VIEW')
|
|
5701
|
+
ORDER BY table_name`
|
|
5295
5702
|
);
|
|
5296
|
-
return rows.map((r) => String(r["
|
|
5703
|
+
return rows.map((r) => String(r["table_name"] ?? "")).filter((name) => name);
|
|
5297
5704
|
}
|
|
5298
5705
|
var redshiftSetupFlow = {
|
|
5299
5706
|
initialState: () => ({}),
|
|
@@ -5308,9 +5715,11 @@ var redshiftSetupFlow = {
|
|
|
5308
5715
|
async fetchOptions(_state, rt) {
|
|
5309
5716
|
const rows = await runQuery7(
|
|
5310
5717
|
rt.params,
|
|
5311
|
-
`SELECT DISTINCT
|
|
5718
|
+
`SELECT DISTINCT table_schema FROM information_schema.tables
|
|
5719
|
+
WHERE table_type IN ('BASE TABLE', 'VIEW')
|
|
5720
|
+
ORDER BY table_schema`
|
|
5312
5721
|
);
|
|
5313
|
-
return rows.map((r) => String(r["
|
|
5722
|
+
return rows.map((r) => String(r["table_schema"] ?? "")).filter((name) => name && !isInternalSchema2(name)).map((value) => ({ value }));
|
|
5314
5723
|
},
|
|
5315
5724
|
applyAnswer: (state, answer) => ({ ...state, schema: answer[0] })
|
|
5316
5725
|
},
|
|
@@ -5318,17 +5727,17 @@ var redshiftSetupFlow = {
|
|
|
5318
5727
|
slug: "tables",
|
|
5319
5728
|
type: "multiSelect",
|
|
5320
5729
|
question: {
|
|
5321
|
-
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
5322
|
-
en: "Select target tables (multi-select allowed)"
|
|
5730
|
+
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
5731
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
5323
5732
|
},
|
|
5324
5733
|
async fetchOptions(state, rt) {
|
|
5325
5734
|
if (!state.schema) return [];
|
|
5326
|
-
const names = await
|
|
5735
|
+
const names = await fetchTableAndViewNames(rt.params, state.schema);
|
|
5327
5736
|
const tableOptions = names.map((value) => ({ value }));
|
|
5328
5737
|
return [
|
|
5329
5738
|
{
|
|
5330
5739
|
value: ALL_TABLES7,
|
|
5331
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
5740
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
5332
5741
|
},
|
|
5333
5742
|
...tableOptions
|
|
5334
5743
|
];
|
|
@@ -5344,9 +5753,21 @@ var redshiftSetupFlow = {
|
|
|
5344
5753
|
const targetTables = await resolveSetupSelection({
|
|
5345
5754
|
selected: state.tables,
|
|
5346
5755
|
allSentinel: ALL_TABLES7,
|
|
5347
|
-
fetchAll: () =>
|
|
5756
|
+
fetchAll: () => fetchTableAndViewNames(rt.params, schema),
|
|
5348
5757
|
limit: REDSHIFT_SETUP_MAX_TABLES
|
|
5349
5758
|
});
|
|
5759
|
+
const typeRows = targetTables.length > 0 ? await runQuery7(
|
|
5760
|
+
rt.params,
|
|
5761
|
+
`SELECT table_name, table_type FROM information_schema.tables
|
|
5762
|
+
WHERE table_schema = ${quoteLiteral(schema)}
|
|
5763
|
+
AND table_name IN (${targetTables.map(quoteLiteral).join(", ")})`
|
|
5764
|
+
) : [];
|
|
5765
|
+
const typeMap = new Map(
|
|
5766
|
+
typeRows.map((r) => [
|
|
5767
|
+
String(r["table_name"] ?? ""),
|
|
5768
|
+
String(r["table_type"] ?? "BASE TABLE")
|
|
5769
|
+
])
|
|
5770
|
+
);
|
|
5350
5771
|
const sections = [
|
|
5351
5772
|
"## Redshift",
|
|
5352
5773
|
"",
|
|
@@ -5354,6 +5775,7 @@ var redshiftSetupFlow = {
|
|
|
5354
5775
|
""
|
|
5355
5776
|
];
|
|
5356
5777
|
for (const table of targetTables) {
|
|
5778
|
+
const heading = typeMap.get(table) === "VIEW" ? "View" : "Table";
|
|
5357
5779
|
const cols = await runQuery7(
|
|
5358
5780
|
rt.params,
|
|
5359
5781
|
`SELECT column_name, data_type, is_nullable, column_default
|
|
@@ -5362,7 +5784,7 @@ var redshiftSetupFlow = {
|
|
|
5362
5784
|
AND table_name = ${quoteLiteral(table)}
|
|
5363
5785
|
ORDER BY ordinal_position`
|
|
5364
5786
|
);
|
|
5365
|
-
sections.push(`####
|
|
5787
|
+
sections.push(`#### ${heading}: ${table}`, "");
|
|
5366
5788
|
sections.push("| Column | Type | Nullable | Default |");
|
|
5367
5789
|
sections.push("|--------|------|----------|---------|");
|
|
5368
5790
|
for (const c of cols) {
|
|
@@ -5790,8 +6212,8 @@ var databricksSetupFlow = {
|
|
|
5790
6212
|
slug: "tables",
|
|
5791
6213
|
type: "multiSelect",
|
|
5792
6214
|
question: {
|
|
5793
|
-
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
5794
|
-
en: "Select target tables (multi-select allowed)"
|
|
6215
|
+
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
6216
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
5795
6217
|
},
|
|
5796
6218
|
async fetchOptions(state, rt) {
|
|
5797
6219
|
if (!state.catalog || !state.schema) return [];
|
|
@@ -5803,7 +6225,7 @@ var databricksSetupFlow = {
|
|
|
5803
6225
|
return [
|
|
5804
6226
|
{
|
|
5805
6227
|
value: ALL_TABLES8,
|
|
5806
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
6228
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
5807
6229
|
},
|
|
5808
6230
|
...tableOptions
|
|
5809
6231
|
];
|
|
@@ -7183,11 +7605,11 @@ var parameters13 = {
|
|
|
7183
7605
|
propertyId: new ParameterDefinition({
|
|
7184
7606
|
slug: "property-id",
|
|
7185
7607
|
name: "Google Analytics Property ID",
|
|
7186
|
-
description: "The Google Analytics 4 property ID (e.g., 123456789).",
|
|
7608
|
+
description: "The Google Analytics 4 property ID (e.g., 123456789). Automatically set during the setup flow.",
|
|
7187
7609
|
envVarBaseKey: "GA_PROPERTY_ID",
|
|
7188
7610
|
type: "text",
|
|
7189
7611
|
secret: false,
|
|
7190
|
-
required:
|
|
7612
|
+
required: false
|
|
7191
7613
|
})
|
|
7192
7614
|
};
|
|
7193
7615
|
|
|
@@ -7195,6 +7617,7 @@ var parameters13 = {
|
|
|
7195
7617
|
import * as crypto2 from "crypto";
|
|
7196
7618
|
var TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
7197
7619
|
var ADMIN_BASE_URL = "https://analyticsadmin.googleapis.com/v1beta";
|
|
7620
|
+
var DATA_BASE_URL = "https://analyticsdata.googleapis.com/v1beta";
|
|
7198
7621
|
var SCOPE = "https://www.googleapis.com/auth/analytics.readonly";
|
|
7199
7622
|
function base64url(input) {
|
|
7200
7623
|
const buf = typeof input === "string" ? Buffer.from(input) : input;
|
|
@@ -7276,10 +7699,25 @@ async function adminFetch(params, path5, init) {
|
|
|
7276
7699
|
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
7277
7700
|
return fetch(url, { ...init, headers });
|
|
7278
7701
|
}
|
|
7702
|
+
async function dataFetch(params, path5, init) {
|
|
7703
|
+
const keyJsonBase64 = params[parameters13.serviceAccountKeyJsonBase64.slug];
|
|
7704
|
+
if (!keyJsonBase64) {
|
|
7705
|
+
throw new Error(
|
|
7706
|
+
"google-analytics: missing required parameter: service-account-key-json-base64"
|
|
7707
|
+
);
|
|
7708
|
+
}
|
|
7709
|
+
const serviceAccountKey = decodeServiceAccount(keyJsonBase64);
|
|
7710
|
+
const accessToken = await getAccessToken(serviceAccountKey);
|
|
7711
|
+
const url = `${DATA_BASE_URL}${path5.startsWith("/") ? "" : "/"}${path5}`;
|
|
7712
|
+
const headers = new Headers(init?.headers);
|
|
7713
|
+
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
7714
|
+
return fetch(url, { ...init, headers });
|
|
7715
|
+
}
|
|
7279
7716
|
|
|
7280
7717
|
// ../connectors/src/connectors/google-analytics/setup-flow.ts
|
|
7281
7718
|
var ALL_PROPERTIES = "__ALL_PROPERTIES__";
|
|
7282
7719
|
var GOOGLE_ANALYTICS_SETUP_MAX_PROPERTIES = 20;
|
|
7720
|
+
var METADATA_DISPLAY_LIMIT = 30;
|
|
7283
7721
|
async function listAccountSummaries(params) {
|
|
7284
7722
|
const summaries = [];
|
|
7285
7723
|
let pageToken;
|
|
@@ -7306,6 +7744,48 @@ async function getProperty(params, propertyId) {
|
|
|
7306
7744
|
if (!res.ok) return null;
|
|
7307
7745
|
return await res.json();
|
|
7308
7746
|
}
|
|
7747
|
+
async function getMetadata(params, propertyId) {
|
|
7748
|
+
try {
|
|
7749
|
+
const res = await dataFetch(
|
|
7750
|
+
params,
|
|
7751
|
+
`/properties/${propertyId}/metadata`
|
|
7752
|
+
);
|
|
7753
|
+
if (!res.ok) return { dimensions: [], metrics: [] };
|
|
7754
|
+
const data = await res.json();
|
|
7755
|
+
return {
|
|
7756
|
+
dimensions: data.dimensions ?? [],
|
|
7757
|
+
metrics: data.metrics ?? []
|
|
7758
|
+
};
|
|
7759
|
+
} catch {
|
|
7760
|
+
return { dimensions: [], metrics: [] };
|
|
7761
|
+
}
|
|
7762
|
+
}
|
|
7763
|
+
function appendMetadataSection(sections, dimensions, metrics) {
|
|
7764
|
+
if (dimensions.length > 0) {
|
|
7765
|
+
sections.push(`#### Dimensions (${dimensions.length})`, "");
|
|
7766
|
+
for (const d of dimensions.slice(0, METADATA_DISPLAY_LIMIT)) {
|
|
7767
|
+
sections.push(`- ${d.apiName ?? d.uiName ?? "(unknown)"}`);
|
|
7768
|
+
}
|
|
7769
|
+
if (dimensions.length > METADATA_DISPLAY_LIMIT) {
|
|
7770
|
+
sections.push(
|
|
7771
|
+
`- \u2026and ${dimensions.length - METADATA_DISPLAY_LIMIT} more`
|
|
7772
|
+
);
|
|
7773
|
+
}
|
|
7774
|
+
sections.push("");
|
|
7775
|
+
}
|
|
7776
|
+
if (metrics.length > 0) {
|
|
7777
|
+
sections.push(`#### Metrics (${metrics.length})`, "");
|
|
7778
|
+
for (const m of metrics.slice(0, METADATA_DISPLAY_LIMIT)) {
|
|
7779
|
+
sections.push(`- ${m.apiName ?? m.uiName ?? "(unknown)"}`);
|
|
7780
|
+
}
|
|
7781
|
+
if (metrics.length > METADATA_DISPLAY_LIMIT) {
|
|
7782
|
+
sections.push(
|
|
7783
|
+
`- \u2026and ${metrics.length - METADATA_DISPLAY_LIMIT} more`
|
|
7784
|
+
);
|
|
7785
|
+
}
|
|
7786
|
+
sections.push("");
|
|
7787
|
+
}
|
|
7788
|
+
}
|
|
7309
7789
|
var googleAnalyticsSetupFlow = {
|
|
7310
7790
|
initialState: () => ({}),
|
|
7311
7791
|
steps: [
|
|
@@ -7317,15 +7797,19 @@ var googleAnalyticsSetupFlow = {
|
|
|
7317
7797
|
en: "Select a Google Analytics account"
|
|
7318
7798
|
},
|
|
7319
7799
|
async fetchOptions(_state, rt) {
|
|
7320
|
-
|
|
7321
|
-
|
|
7322
|
-
|
|
7323
|
-
|
|
7324
|
-
|
|
7325
|
-
|
|
7326
|
-
|
|
7327
|
-
|
|
7328
|
-
|
|
7800
|
+
try {
|
|
7801
|
+
const summaries = await listAccountSummaries(rt.params);
|
|
7802
|
+
return summaries.map((s) => {
|
|
7803
|
+
const accountResource = s.account ?? s.name ?? "";
|
|
7804
|
+
if (!accountResource) return null;
|
|
7805
|
+
return {
|
|
7806
|
+
value: accountResource,
|
|
7807
|
+
label: s.displayName ?? accountResource
|
|
7808
|
+
};
|
|
7809
|
+
}).filter((v) => v != null);
|
|
7810
|
+
} catch {
|
|
7811
|
+
return [];
|
|
7812
|
+
}
|
|
7329
7813
|
},
|
|
7330
7814
|
applyAnswer: (state, answer) => ({ ...state, account: answer[0] })
|
|
7331
7815
|
},
|
|
@@ -7338,68 +7822,134 @@ var googleAnalyticsSetupFlow = {
|
|
|
7338
7822
|
},
|
|
7339
7823
|
async fetchOptions(state, rt) {
|
|
7340
7824
|
if (!state.account) return [];
|
|
7341
|
-
|
|
7342
|
-
|
|
7343
|
-
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
const
|
|
7347
|
-
|
|
7348
|
-
|
|
7349
|
-
|
|
7350
|
-
|
|
7351
|
-
|
|
7352
|
-
|
|
7353
|
-
|
|
7354
|
-
|
|
7825
|
+
try {
|
|
7826
|
+
const summaries = await listAccountSummaries(rt.params);
|
|
7827
|
+
const account = summaries.find(
|
|
7828
|
+
(s) => (s.account ?? s.name) === state.account
|
|
7829
|
+
);
|
|
7830
|
+
const props = (account?.propertySummaries ?? []).map((p) => {
|
|
7831
|
+
const id = propertyIdFromResource(p.property);
|
|
7832
|
+
if (!id) return null;
|
|
7833
|
+
return {
|
|
7834
|
+
value: id,
|
|
7835
|
+
label: p.displayName ? `${p.displayName} (${id})` : id
|
|
7836
|
+
};
|
|
7837
|
+
}).filter((v) => v != null);
|
|
7838
|
+
if (props.length === 0) return [];
|
|
7839
|
+
return [
|
|
7840
|
+
{
|
|
7841
|
+
value: ALL_PROPERTIES,
|
|
7842
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30D7\u30ED\u30D1\u30C6\u30A3" : "All properties"
|
|
7843
|
+
},
|
|
7844
|
+
...props
|
|
7845
|
+
];
|
|
7846
|
+
} catch {
|
|
7847
|
+
return [];
|
|
7848
|
+
}
|
|
7849
|
+
},
|
|
7850
|
+
applyAnswer: (state, answer) => ({ ...state, properties: answer }),
|
|
7851
|
+
toParameterUpdates: (state) => {
|
|
7852
|
+
const first = state.properties?.find((v) => v !== ALL_PROPERTIES);
|
|
7853
|
+
return first ? [{ slug: parameters13.propertyId.slug, value: first }] : [];
|
|
7854
|
+
}
|
|
7855
|
+
},
|
|
7856
|
+
{
|
|
7857
|
+
slug: "manualPropertyId",
|
|
7858
|
+
type: "select",
|
|
7859
|
+
allowFreeText: true,
|
|
7860
|
+
question: {
|
|
7861
|
+
ja: "GA4 \u30D7\u30ED\u30D1\u30C6\u30A3 ID \u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u4F8B: 123456789\uFF09\u3002GA4 \u7BA1\u7406\u753B\u9762 > \u30D7\u30ED\u30D1\u30C6\u30A3\u8A2D\u5B9A\u3067\u78BA\u8A8D\u3067\u304D\u307E\u3059\u3002",
|
|
7862
|
+
en: "Enter your GA4 Property ID (e.g., 123456789). Found in GA4 Admin > Property Settings."
|
|
7863
|
+
},
|
|
7864
|
+
async fetchOptions(state, rt) {
|
|
7865
|
+
if (state.properties?.length) return [];
|
|
7866
|
+
const existing = rt.params[parameters13.propertyId.slug];
|
|
7867
|
+
return existing ? [{ value: existing, label: existing }] : [
|
|
7355
7868
|
{
|
|
7356
|
-
value:
|
|
7357
|
-
label: rt.language === "ja" ? "\
|
|
7358
|
-
}
|
|
7359
|
-
...props
|
|
7869
|
+
value: "example",
|
|
7870
|
+
label: rt.language === "ja" ? "\u4F8B: 123456789" : "Example: 123456789"
|
|
7871
|
+
}
|
|
7360
7872
|
];
|
|
7361
7873
|
},
|
|
7362
|
-
applyAnswer: (state, answer) => ({
|
|
7874
|
+
applyAnswer: (state, answer) => ({
|
|
7875
|
+
...state,
|
|
7876
|
+
manualPropertyId: answer[0]
|
|
7877
|
+
}),
|
|
7878
|
+
toParameterUpdates: (state) => state.manualPropertyId ? [
|
|
7879
|
+
{
|
|
7880
|
+
slug: parameters13.propertyId.slug,
|
|
7881
|
+
value: state.manualPropertyId
|
|
7882
|
+
}
|
|
7883
|
+
] : []
|
|
7363
7884
|
}
|
|
7364
7885
|
],
|
|
7365
7886
|
async finalize(state, rt) {
|
|
7366
|
-
|
|
7367
|
-
|
|
7368
|
-
|
|
7369
|
-
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
|
|
7374
|
-
|
|
7375
|
-
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
|
|
7379
|
-
|
|
7380
|
-
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
`### Account: ${accountLabel2}`,
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7887
|
+
const sections = ["## Google Analytics", ""];
|
|
7888
|
+
if (state.account && state.properties) {
|
|
7889
|
+
let summaries = [];
|
|
7890
|
+
try {
|
|
7891
|
+
summaries = await listAccountSummaries(rt.params);
|
|
7892
|
+
} catch {
|
|
7893
|
+
}
|
|
7894
|
+
const account = summaries.find(
|
|
7895
|
+
(s) => (s.account ?? s.name) === state.account
|
|
7896
|
+
);
|
|
7897
|
+
const accountLabel2 = account?.displayName ?? state.account.replace(/^accounts\//, "");
|
|
7898
|
+
const targetPropertyIds = await resolveSetupSelection({
|
|
7899
|
+
selected: state.properties,
|
|
7900
|
+
allSentinel: ALL_PROPERTIES,
|
|
7901
|
+
fetchAll: async () => (account?.propertySummaries ?? []).map((p) => propertyIdFromResource(p.property)).filter((v) => v),
|
|
7902
|
+
limit: GOOGLE_ANALYTICS_SETUP_MAX_PROPERTIES
|
|
7903
|
+
});
|
|
7904
|
+
sections.push(`### Account: ${accountLabel2}`, "");
|
|
7905
|
+
if (targetPropertyIds.length === 0) {
|
|
7906
|
+
sections.push("_No properties selected._", "");
|
|
7907
|
+
return sections.join("\n");
|
|
7908
|
+
}
|
|
7909
|
+
sections.push(
|
|
7910
|
+
"| Property ID | Display Name | Time Zone | Currency | Industry |"
|
|
7911
|
+
);
|
|
7912
|
+
sections.push(
|
|
7913
|
+
"|-------------|--------------|-----------|----------|----------|"
|
|
7914
|
+
);
|
|
7915
|
+
for (const pid of targetPropertyIds) {
|
|
7916
|
+
const prop = await getProperty(rt.params, pid).catch(() => null);
|
|
7917
|
+
const displayName3 = (prop?.displayName ?? "-").replace(/\|/g, "\\|");
|
|
7918
|
+
const timeZone = prop?.timeZone ?? "-";
|
|
7919
|
+
const currency = prop?.currencyCode ?? "-";
|
|
7920
|
+
const industry = (prop?.industryCategory ?? "-").replace(
|
|
7921
|
+
/\|/g,
|
|
7922
|
+
"\\|"
|
|
7923
|
+
);
|
|
7924
|
+
sections.push(
|
|
7925
|
+
`| ${pid} | ${displayName3} | ${timeZone} | ${currency} | ${industry} |`
|
|
7926
|
+
);
|
|
7927
|
+
}
|
|
7928
|
+
sections.push("");
|
|
7929
|
+
const firstPropertyId = targetPropertyIds[0];
|
|
7930
|
+
if (firstPropertyId) {
|
|
7931
|
+
const { dimensions, metrics } = await getMetadata(
|
|
7932
|
+
rt.params,
|
|
7933
|
+
firstPropertyId
|
|
7934
|
+
);
|
|
7935
|
+
appendMetadataSection(sections, dimensions, metrics);
|
|
7936
|
+
}
|
|
7388
7937
|
return sections.join("\n");
|
|
7389
7938
|
}
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
const
|
|
7394
|
-
|
|
7395
|
-
|
|
7396
|
-
const currency = prop?.currencyCode ?? "-";
|
|
7397
|
-
const industry = (prop?.industryCategory ?? "-").replace(/\|/g, "\\|");
|
|
7398
|
-
sections.push(
|
|
7399
|
-
`| ${propertyId} | ${displayName3} | ${timeZone} | ${currency} | ${industry} |`
|
|
7939
|
+
const propertyId = state.manualPropertyId ?? rt.params[parameters13.propertyId.slug];
|
|
7940
|
+
if (propertyId) {
|
|
7941
|
+
sections.push(`### Property: ${propertyId}`, "");
|
|
7942
|
+
const { dimensions, metrics } = await getMetadata(
|
|
7943
|
+
rt.params,
|
|
7944
|
+
propertyId
|
|
7400
7945
|
);
|
|
7946
|
+
appendMetadataSection(sections, dimensions, metrics);
|
|
7947
|
+
return sections.join("\n");
|
|
7401
7948
|
}
|
|
7402
|
-
sections.push(
|
|
7949
|
+
sections.push(
|
|
7950
|
+
"_Could not list GA4 accounts. Please enable the Google Analytics Admin API in your GCP project, or set the Property ID parameter manually._",
|
|
7951
|
+
""
|
|
7952
|
+
);
|
|
7403
7953
|
return sections.join("\n");
|
|
7404
7954
|
}
|
|
7405
7955
|
};
|
|
@@ -7647,13 +8197,20 @@ activeUsers, sessions, screenPageViews, bounceRate, averageSessionDuration, conv
|
|
|
7647
8197
|
error: "google-analytics: missing service account key"
|
|
7648
8198
|
};
|
|
7649
8199
|
}
|
|
8200
|
+
const propertyId = params[parameters13.propertyId.slug];
|
|
8201
|
+
if (!propertyId) {
|
|
8202
|
+
return { success: true };
|
|
8203
|
+
}
|
|
7650
8204
|
try {
|
|
7651
|
-
const res = await
|
|
8205
|
+
const res = await dataFetch(
|
|
8206
|
+
params,
|
|
8207
|
+
`/properties/${propertyId}/metadata`
|
|
8208
|
+
);
|
|
7652
8209
|
if (!res.ok) {
|
|
7653
8210
|
const body = await res.text().catch(() => res.statusText);
|
|
7654
8211
|
return {
|
|
7655
8212
|
success: false,
|
|
7656
|
-
error: `
|
|
8213
|
+
error: `Google Analytics API failed: HTTP ${res.status} ${body}`
|
|
7657
8214
|
};
|
|
7658
8215
|
}
|
|
7659
8216
|
return { success: true };
|
|
@@ -19293,7 +19850,7 @@ function escapeIdentifier(name) {
|
|
|
19293
19850
|
function quoteLiteral2(value) {
|
|
19294
19851
|
return "'" + value.replace(/'/g, "''") + "'";
|
|
19295
19852
|
}
|
|
19296
|
-
async function
|
|
19853
|
+
async function fetchTableNames3(params, database) {
|
|
19297
19854
|
const rows = await runQuery9(
|
|
19298
19855
|
params,
|
|
19299
19856
|
`SELECT name FROM system.tables
|
|
@@ -19322,17 +19879,17 @@ var clickhouseSetupFlow = {
|
|
|
19322
19879
|
slug: "tables",
|
|
19323
19880
|
type: "multiSelect",
|
|
19324
19881
|
question: {
|
|
19325
|
-
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
19326
|
-
en: "Select target tables (multi-select allowed)"
|
|
19882
|
+
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
19883
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
19327
19884
|
},
|
|
19328
19885
|
async fetchOptions(state, rt) {
|
|
19329
19886
|
if (!state.database) return [];
|
|
19330
|
-
const names = await
|
|
19887
|
+
const names = await fetchTableNames3(rt.params, state.database);
|
|
19331
19888
|
const tableOptions = names.map((value) => ({ value }));
|
|
19332
19889
|
return [
|
|
19333
19890
|
{
|
|
19334
19891
|
value: ALL_TABLES11,
|
|
19335
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
19892
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
19336
19893
|
},
|
|
19337
19894
|
...tableOptions
|
|
19338
19895
|
];
|
|
@@ -19348,7 +19905,7 @@ var clickhouseSetupFlow = {
|
|
|
19348
19905
|
const targetTables = await resolveSetupSelection({
|
|
19349
19906
|
selected: state.tables,
|
|
19350
19907
|
allSentinel: ALL_TABLES11,
|
|
19351
|
-
fetchAll: () =>
|
|
19908
|
+
fetchAll: () => fetchTableNames3(rt.params, database),
|
|
19352
19909
|
limit: CLICKHOUSE_SETUP_MAX_TABLES
|
|
19353
19910
|
});
|
|
19354
19911
|
const sections = [
|
|
@@ -23947,7 +24504,7 @@ export default async function handler(c: Context) {
|
|
|
23947
24504
|
const region = params[parameters50.region.slug];
|
|
23948
24505
|
const baseUrl = region === "eu" ? "https://api-eu.customer.io" : "https://api.customer.io";
|
|
23949
24506
|
try {
|
|
23950
|
-
const res = await fetch(`${baseUrl}/v1/
|
|
24507
|
+
const res = await fetch(`${baseUrl}/v1/segments`, {
|
|
23951
24508
|
method: "GET",
|
|
23952
24509
|
headers: {
|
|
23953
24510
|
Authorization: `Bearer ${appApiKey}`,
|
|
@@ -29503,7 +30060,7 @@ function apiFetch27(params, path5, init) {
|
|
|
29503
30060
|
// ../connectors/src/connectors/gamma/setup-flow.ts
|
|
29504
30061
|
var ALL_FOLDERS = "__ALL_FOLDERS__";
|
|
29505
30062
|
var GAMMA_SETUP_MAX_FOLDERS = 20;
|
|
29506
|
-
var FOLDERS_PAGE_LIMIT =
|
|
30063
|
+
var FOLDERS_PAGE_LIMIT = 50;
|
|
29507
30064
|
async function listAllFolders(params) {
|
|
29508
30065
|
const results = [];
|
|
29509
30066
|
let after;
|
|
@@ -29524,7 +30081,7 @@ async function listAllFolders(params) {
|
|
|
29524
30081
|
return results;
|
|
29525
30082
|
}
|
|
29526
30083
|
async function listThemes(params) {
|
|
29527
|
-
const res = await apiFetch27(params, "/themes?limit=
|
|
30084
|
+
const res = await apiFetch27(params, "/themes?limit=50");
|
|
29528
30085
|
if (!res.ok) {
|
|
29529
30086
|
return [];
|
|
29530
30087
|
}
|
|
@@ -33361,7 +33918,8 @@ var semrushOnboarding = new ConnectorOnboarding({
|
|
|
33361
33918
|
});
|
|
33362
33919
|
|
|
33363
33920
|
// ../connectors/src/connectors/semrush/utils.ts
|
|
33364
|
-
var
|
|
33921
|
+
var BASE_URL59 = "https://api.semrush.com";
|
|
33922
|
+
var PROJECTS_BASE_URL = `${BASE_URL59}/management/v1`;
|
|
33365
33923
|
function projectsApiFetch(params, path5, init) {
|
|
33366
33924
|
const apiKey = params[parameters68.apiKey.slug];
|
|
33367
33925
|
if (!apiKey) {
|
|
@@ -33378,10 +33936,103 @@ function projectsApiFetch(params, path5, init) {
|
|
|
33378
33936
|
if (!headers.has("Accept")) headers.set("Accept", "application/json");
|
|
33379
33937
|
return fetch(url.toString(), { ...init, headers });
|
|
33380
33938
|
}
|
|
33939
|
+
async function reportFetch(params, query) {
|
|
33940
|
+
const apiKey = params[parameters68.apiKey.slug];
|
|
33941
|
+
if (!apiKey) {
|
|
33942
|
+
throw new Error(
|
|
33943
|
+
`semrush: missing required parameter: ${parameters68.apiKey.slug}`
|
|
33944
|
+
);
|
|
33945
|
+
}
|
|
33946
|
+
const url = new URL(`${BASE_URL59}/`);
|
|
33947
|
+
for (const [k, v] of Object.entries(query)) {
|
|
33948
|
+
url.searchParams.set(k, v);
|
|
33949
|
+
}
|
|
33950
|
+
url.searchParams.set("key", apiKey);
|
|
33951
|
+
const res = await fetch(url.toString());
|
|
33952
|
+
const text = await res.text();
|
|
33953
|
+
if (text.startsWith("ERROR ")) throw new Error(text.trim());
|
|
33954
|
+
return parseSemicolonCsv(text);
|
|
33955
|
+
}
|
|
33956
|
+
async function backlinksFetch(params, query) {
|
|
33957
|
+
const apiKey = params[parameters68.apiKey.slug];
|
|
33958
|
+
if (!apiKey) {
|
|
33959
|
+
throw new Error(
|
|
33960
|
+
`semrush: missing required parameter: ${parameters68.apiKey.slug}`
|
|
33961
|
+
);
|
|
33962
|
+
}
|
|
33963
|
+
const url = new URL(`${BASE_URL59}/analytics/v1/`);
|
|
33964
|
+
for (const [k, v] of Object.entries(query)) {
|
|
33965
|
+
url.searchParams.set(k, v);
|
|
33966
|
+
}
|
|
33967
|
+
url.searchParams.set("key", apiKey);
|
|
33968
|
+
const res = await fetch(url.toString());
|
|
33969
|
+
const text = await res.text();
|
|
33970
|
+
if (text.startsWith("ERROR ")) throw new Error(text.trim());
|
|
33971
|
+
return parseSemicolonCsv(text);
|
|
33972
|
+
}
|
|
33973
|
+
function parseSemicolonCsv(raw) {
|
|
33974
|
+
const lines = raw.trim().split("\n").filter(Boolean);
|
|
33975
|
+
if (lines.length === 0) return { columns: [], rows: [] };
|
|
33976
|
+
const columns = lines[0].split(";");
|
|
33977
|
+
const rows = lines.slice(1).map((line) => {
|
|
33978
|
+
const values = line.split(";");
|
|
33979
|
+
const row = {};
|
|
33980
|
+
for (let i = 0; i < columns.length; i++) {
|
|
33981
|
+
row[columns[i]] = values[i] ?? "";
|
|
33982
|
+
}
|
|
33983
|
+
return row;
|
|
33984
|
+
});
|
|
33985
|
+
return { columns, rows };
|
|
33986
|
+
}
|
|
33381
33987
|
|
|
33382
33988
|
// ../connectors/src/connectors/semrush/setup-flow.ts
|
|
33383
33989
|
var ALL_PROJECTS6 = "__ALL_PROJECTS__";
|
|
33384
33990
|
var SEMRUSH_SETUP_MAX_PROJECTS = 10;
|
|
33991
|
+
var SEMRUSH_DATABASES = [
|
|
33992
|
+
{ value: "us", label: "United States" },
|
|
33993
|
+
{ value: "uk", label: "United Kingdom" },
|
|
33994
|
+
{ value: "ca", label: "Canada" },
|
|
33995
|
+
{ value: "au", label: "Australia" },
|
|
33996
|
+
{ value: "de", label: "Germany" },
|
|
33997
|
+
{ value: "fr", label: "France" },
|
|
33998
|
+
{ value: "es", label: "Spain" },
|
|
33999
|
+
{ value: "it", label: "Italy" },
|
|
34000
|
+
{ value: "br", label: "Brazil" },
|
|
34001
|
+
{ value: "jp", label: "Japan" },
|
|
34002
|
+
{ value: "in", label: "India" },
|
|
34003
|
+
{ value: "ru", label: "Russia" },
|
|
34004
|
+
{ value: "nl", label: "Netherlands" },
|
|
34005
|
+
{ value: "se", label: "Sweden" },
|
|
34006
|
+
{ value: "mx", label: "Mexico" },
|
|
34007
|
+
{ value: "kr", label: "South Korea" },
|
|
34008
|
+
{ value: "sg", label: "Singapore" },
|
|
34009
|
+
{ value: "hk", label: "Hong Kong" },
|
|
34010
|
+
{ value: "tw", label: "Taiwan" }
|
|
34011
|
+
];
|
|
34012
|
+
var REPORT_TYPE_LABELS = {
|
|
34013
|
+
domain_overview: {
|
|
34014
|
+
en: "Domain Overview (rank, traffic, keyword count)",
|
|
34015
|
+
ja: "Domain Overview (\u30E9\u30F3\u30AF\u30FB\u30C8\u30E9\u30D5\u30A3\u30C3\u30AF\u30FB\u30AD\u30FC\u30EF\u30FC\u30C9\u6570)"
|
|
34016
|
+
},
|
|
34017
|
+
organic_search: {
|
|
34018
|
+
en: "Organic Search (top organic keywords)",
|
|
34019
|
+
ja: "Organic Search (\u4E0A\u4F4D\u30AA\u30FC\u30AC\u30CB\u30C3\u30AF\u30AD\u30FC\u30EF\u30FC\u30C9)"
|
|
34020
|
+
},
|
|
34021
|
+
paid_search: {
|
|
34022
|
+
en: "Paid Search (top paid keywords)",
|
|
34023
|
+
ja: "Paid Search (\u4E0A\u4F4D\u6709\u6599\u30AD\u30FC\u30EF\u30FC\u30C9)"
|
|
34024
|
+
},
|
|
34025
|
+
backlinks: {
|
|
34026
|
+
en: "Backlinks (referring domains, backlink count)",
|
|
34027
|
+
ja: "Backlinks (\u53C2\u7167\u30C9\u30E1\u30A4\u30F3\u30FB\u88AB\u30EA\u30F3\u30AF\u6570)"
|
|
34028
|
+
}
|
|
34029
|
+
};
|
|
34030
|
+
var REPORT_TYPE_VALUES = [
|
|
34031
|
+
"domain_overview",
|
|
34032
|
+
"organic_search",
|
|
34033
|
+
"paid_search",
|
|
34034
|
+
"backlinks"
|
|
34035
|
+
];
|
|
33385
34036
|
function projectId(p) {
|
|
33386
34037
|
const raw = p.project_id ?? p.id;
|
|
33387
34038
|
return raw == null ? "" : String(raw);
|
|
@@ -33390,7 +34041,7 @@ function projectName(p) {
|
|
|
33390
34041
|
return p.project_name ?? p.name ?? p.domain ?? p.url ?? projectId(p);
|
|
33391
34042
|
}
|
|
33392
34043
|
function projectDomain(p) {
|
|
33393
|
-
return p.domain ?? p.url ?? "";
|
|
34044
|
+
return p.domain ?? p.domain_unicode ?? p.url ?? "";
|
|
33394
34045
|
}
|
|
33395
34046
|
function projectCreatedAt(p) {
|
|
33396
34047
|
return p.created_at ?? p.date_created ?? "";
|
|
@@ -33398,13 +34049,19 @@ function projectCreatedAt(p) {
|
|
|
33398
34049
|
async function fetchProjects(params) {
|
|
33399
34050
|
let res;
|
|
33400
34051
|
try {
|
|
33401
|
-
res = await projectsApiFetch(params, "/projects
|
|
34052
|
+
res = await projectsApiFetch(params, "/projects");
|
|
33402
34053
|
} catch (err) {
|
|
33403
|
-
return {
|
|
34054
|
+
return {
|
|
34055
|
+
ok: false,
|
|
34056
|
+
error: err instanceof Error ? err.message : String(err)
|
|
34057
|
+
};
|
|
33404
34058
|
}
|
|
33405
34059
|
if (!res.ok) {
|
|
33406
34060
|
const body2 = await res.text().catch(() => res.statusText);
|
|
33407
|
-
return {
|
|
34061
|
+
return {
|
|
34062
|
+
ok: false,
|
|
34063
|
+
error: `HTTP ${res.status} ${body2 || res.statusText}`
|
|
34064
|
+
};
|
|
33408
34065
|
}
|
|
33409
34066
|
let body;
|
|
33410
34067
|
try {
|
|
@@ -33418,9 +34075,171 @@ async function fetchProjects(params) {
|
|
|
33418
34075
|
const projects = Array.isArray(body) ? body : Array.isArray(body?.projects) ? body.projects : Array.isArray(body?.data) ? body.data : [];
|
|
33419
34076
|
return { ok: true, projects };
|
|
33420
34077
|
}
|
|
34078
|
+
function formatNumber(n) {
|
|
34079
|
+
return n.toLocaleString("en-US");
|
|
34080
|
+
}
|
|
34081
|
+
async function fetchDomainOverview(params, domain, database) {
|
|
34082
|
+
const sections = [];
|
|
34083
|
+
try {
|
|
34084
|
+
const report = await reportFetch(params, {
|
|
34085
|
+
type: "domain_ranks",
|
|
34086
|
+
domain,
|
|
34087
|
+
database
|
|
34088
|
+
});
|
|
34089
|
+
if (report.rows.length === 0) {
|
|
34090
|
+
sections.push("_No data found for this domain._", "");
|
|
34091
|
+
return sections;
|
|
34092
|
+
}
|
|
34093
|
+
const row = report.rows[0];
|
|
34094
|
+
sections.push("| Metric | Value |");
|
|
34095
|
+
sections.push("|--------|-------|");
|
|
34096
|
+
sections.push(
|
|
34097
|
+
`| Rank | ${row["Rank"] ?? "-"} |`,
|
|
34098
|
+
`| Organic Keywords | ${formatNumber(Number(row["Organic Keywords"]) || 0)} |`,
|
|
34099
|
+
`| Organic Traffic | ${formatNumber(Number(row["Organic Traffic"]) || 0)} |`,
|
|
34100
|
+
`| Organic Cost | $${formatNumber(Number(row["Organic Cost"]) || 0)} |`,
|
|
34101
|
+
`| Adwords Keywords | ${formatNumber(Number(row["Adwords Keywords"]) || 0)} |`,
|
|
34102
|
+
`| Adwords Traffic | ${formatNumber(Number(row["Adwords Traffic"]) || 0)} |`,
|
|
34103
|
+
`| Adwords Cost | $${formatNumber(Number(row["Adwords Cost"]) || 0)} |`
|
|
34104
|
+
);
|
|
34105
|
+
sections.push("");
|
|
34106
|
+
} catch (err) {
|
|
34107
|
+
sections.push(
|
|
34108
|
+
`_Error: ${err instanceof Error ? err.message : String(err)}_`,
|
|
34109
|
+
""
|
|
34110
|
+
);
|
|
34111
|
+
}
|
|
34112
|
+
return sections;
|
|
34113
|
+
}
|
|
34114
|
+
async function fetchOrganicSearch(params, domain, database) {
|
|
34115
|
+
return fetchKeywordReport(params, "domain_organic", domain, database);
|
|
34116
|
+
}
|
|
34117
|
+
async function fetchPaidSearch(params, domain, database) {
|
|
34118
|
+
return fetchKeywordReport(params, "domain_adwords", domain, database);
|
|
34119
|
+
}
|
|
34120
|
+
async function fetchKeywordReport(params, type, domain, database) {
|
|
34121
|
+
const sections = [];
|
|
34122
|
+
try {
|
|
34123
|
+
const report = await reportFetch(params, {
|
|
34124
|
+
type,
|
|
34125
|
+
domain,
|
|
34126
|
+
database,
|
|
34127
|
+
display_limit: "5"
|
|
34128
|
+
});
|
|
34129
|
+
if (report.rows.length === 0) {
|
|
34130
|
+
sections.push("_No data found._", "");
|
|
34131
|
+
return sections;
|
|
34132
|
+
}
|
|
34133
|
+
sections.push(...renderCsvTable(report, 5));
|
|
34134
|
+
sections.push("");
|
|
34135
|
+
} catch (err) {
|
|
34136
|
+
sections.push(
|
|
34137
|
+
`_Error: ${err instanceof Error ? err.message : String(err)}_`,
|
|
34138
|
+
""
|
|
34139
|
+
);
|
|
34140
|
+
}
|
|
34141
|
+
return sections;
|
|
34142
|
+
}
|
|
34143
|
+
async function fetchBacklinks(params, domain) {
|
|
34144
|
+
const sections = [];
|
|
34145
|
+
try {
|
|
34146
|
+
const report = await backlinksFetch(params, {
|
|
34147
|
+
type: "backlinks_overview",
|
|
34148
|
+
target: domain,
|
|
34149
|
+
target_type: "root_domain"
|
|
34150
|
+
});
|
|
34151
|
+
if (report.rows.length === 0) {
|
|
34152
|
+
sections.push("_No backlink data found._", "");
|
|
34153
|
+
return sections;
|
|
34154
|
+
}
|
|
34155
|
+
const row = report.rows[0];
|
|
34156
|
+
sections.push("| Metric | Value |");
|
|
34157
|
+
sections.push("|--------|-------|");
|
|
34158
|
+
for (const col of report.columns) {
|
|
34159
|
+
sections.push(`| ${col} | ${formatNumber(Number(row[col]) || 0)} |`);
|
|
34160
|
+
}
|
|
34161
|
+
sections.push("");
|
|
34162
|
+
} catch (err) {
|
|
34163
|
+
sections.push(
|
|
34164
|
+
`_Error: ${err instanceof Error ? err.message : String(err)}_`,
|
|
34165
|
+
""
|
|
34166
|
+
);
|
|
34167
|
+
}
|
|
34168
|
+
return sections;
|
|
34169
|
+
}
|
|
34170
|
+
function renderCsvTable(report, maxRows) {
|
|
34171
|
+
const cols = report.columns;
|
|
34172
|
+
const rows = report.rows.slice(0, maxRows);
|
|
34173
|
+
const lines = [];
|
|
34174
|
+
lines.push(`| ${cols.join(" | ")} |`);
|
|
34175
|
+
lines.push(`|${cols.map(() => "---").join("|")}|`);
|
|
34176
|
+
for (const row of rows) {
|
|
34177
|
+
const cells = cols.map((c) => (row[c] ?? "").replace(/\|/g, "\\|"));
|
|
34178
|
+
lines.push(`| ${cells.join(" | ")} |`);
|
|
34179
|
+
}
|
|
34180
|
+
return lines;
|
|
34181
|
+
}
|
|
33421
34182
|
var semrushSetupFlow = {
|
|
33422
34183
|
initialState: () => ({}),
|
|
33423
34184
|
steps: [
|
|
34185
|
+
{
|
|
34186
|
+
slug: "domain",
|
|
34187
|
+
type: "select",
|
|
34188
|
+
allowFreeText: true,
|
|
34189
|
+
question: {
|
|
34190
|
+
ja: "\u5206\u6790\u5BFE\u8C61\u306E\u30C9\u30E1\u30A4\u30F3\u3092\u9078\u629E\u307E\u305F\u306F\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044",
|
|
34191
|
+
en: "Select or enter the domain to analyze"
|
|
34192
|
+
},
|
|
34193
|
+
async fetchOptions(_state, rt) {
|
|
34194
|
+
const result = await fetchProjects(rt.params);
|
|
34195
|
+
if (!result.ok || result.projects.length === 0) return [];
|
|
34196
|
+
const seen = /* @__PURE__ */ new Set();
|
|
34197
|
+
const options = [];
|
|
34198
|
+
for (const p of result.projects) {
|
|
34199
|
+
const d = projectDomain(p);
|
|
34200
|
+
if (d && !seen.has(d)) {
|
|
34201
|
+
seen.add(d);
|
|
34202
|
+
options.push({
|
|
34203
|
+
value: d,
|
|
34204
|
+
label: `${d} (${projectName(p)})`
|
|
34205
|
+
});
|
|
34206
|
+
}
|
|
34207
|
+
}
|
|
34208
|
+
return options;
|
|
34209
|
+
},
|
|
34210
|
+
applyAnswer: (state, answer) => ({ ...state, domain: answer[0] })
|
|
34211
|
+
},
|
|
34212
|
+
{
|
|
34213
|
+
slug: "database",
|
|
34214
|
+
type: "select",
|
|
34215
|
+
allowFreeText: false,
|
|
34216
|
+
question: {
|
|
34217
|
+
ja: "\u30EA\u30FC\u30B8\u30E7\u30F3\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u5BFE\u8C61\u30C9\u30E1\u30A4\u30F3\u306E\u4E3B\u8981\u5E02\u5834\uFF09",
|
|
34218
|
+
en: "Select the region (primary market for the target domain)"
|
|
34219
|
+
},
|
|
34220
|
+
async fetchOptions() {
|
|
34221
|
+
return SEMRUSH_DATABASES.map((db) => ({
|
|
34222
|
+
value: db.value,
|
|
34223
|
+
label: `${db.label} (${db.value})`
|
|
34224
|
+
}));
|
|
34225
|
+
},
|
|
34226
|
+
applyAnswer: (state, answer) => ({ ...state, database: answer[0] })
|
|
34227
|
+
},
|
|
34228
|
+
{
|
|
34229
|
+
slug: "reportTypes",
|
|
34230
|
+
type: "multiSelect",
|
|
34231
|
+
question: {
|
|
34232
|
+
ja: "\u63A2\u7D22\u3059\u308B\u30EC\u30DD\u30FC\u30C8\u7A2E\u5225\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
34233
|
+
en: "Select report types to explore (multi-select allowed)"
|
|
34234
|
+
},
|
|
34235
|
+
async fetchOptions(_state, rt) {
|
|
34236
|
+
return REPORT_TYPE_VALUES.map((value) => ({
|
|
34237
|
+
value,
|
|
34238
|
+
label: REPORT_TYPE_LABELS[value][rt.language]
|
|
34239
|
+
}));
|
|
34240
|
+
},
|
|
34241
|
+
applyAnswer: (state, answer) => ({ ...state, reportTypes: answer })
|
|
34242
|
+
},
|
|
33424
34243
|
{
|
|
33425
34244
|
slug: "projects",
|
|
33426
34245
|
type: "multiSelect",
|
|
@@ -33437,7 +34256,9 @@ var semrushSetupFlow = {
|
|
|
33437
34256
|
const id = projectId(p);
|
|
33438
34257
|
if (!id) return null;
|
|
33439
34258
|
return { value: id, label: projectName(p) };
|
|
33440
|
-
}).filter(
|
|
34259
|
+
}).filter(
|
|
34260
|
+
(opt) => opt !== null
|
|
34261
|
+
);
|
|
33441
34262
|
if (options.length === 0) return [];
|
|
33442
34263
|
return [
|
|
33443
34264
|
{
|
|
@@ -33451,49 +34272,80 @@ var semrushSetupFlow = {
|
|
|
33451
34272
|
}
|
|
33452
34273
|
],
|
|
33453
34274
|
async finalize(state, rt) {
|
|
33454
|
-
|
|
33455
|
-
|
|
34275
|
+
if (!state.domain || !state.database || !state.reportTypes) {
|
|
34276
|
+
throw new Error("Semrush setup: incomplete state on finalize");
|
|
34277
|
+
}
|
|
34278
|
+
const domain = state.domain;
|
|
34279
|
+
const database = state.database;
|
|
34280
|
+
const selected = state.reportTypes.filter(
|
|
34281
|
+
(r) => REPORT_TYPE_VALUES.includes(r)
|
|
34282
|
+
);
|
|
34283
|
+
const sections = [
|
|
34284
|
+
"## Semrush",
|
|
34285
|
+
"",
|
|
34286
|
+
`**Domain:** ${domain}`,
|
|
34287
|
+
`**Region:** ${database}`,
|
|
34288
|
+
""
|
|
34289
|
+
];
|
|
34290
|
+
for (const reportType of selected) {
|
|
33456
34291
|
sections.push(
|
|
33457
|
-
|
|
34292
|
+
`### ${REPORT_TYPE_LABELS[reportType].en}`,
|
|
33458
34293
|
""
|
|
33459
34294
|
);
|
|
33460
|
-
|
|
33461
|
-
|
|
33462
|
-
|
|
33463
|
-
|
|
33464
|
-
|
|
33465
|
-
|
|
33466
|
-
|
|
33467
|
-
|
|
33468
|
-
|
|
33469
|
-
|
|
33470
|
-
|
|
33471
|
-
|
|
33472
|
-
|
|
33473
|
-
|
|
33474
|
-
|
|
33475
|
-
|
|
33476
|
-
|
|
33477
|
-
|
|
33478
|
-
|
|
33479
|
-
|
|
33480
|
-
sections.push("_No projects selected._", "");
|
|
33481
|
-
return sections.join("\n");
|
|
34295
|
+
switch (reportType) {
|
|
34296
|
+
case "domain_overview":
|
|
34297
|
+
sections.push(
|
|
34298
|
+
...await fetchDomainOverview(rt.params, domain, database)
|
|
34299
|
+
);
|
|
34300
|
+
break;
|
|
34301
|
+
case "organic_search":
|
|
34302
|
+
sections.push(
|
|
34303
|
+
...await fetchOrganicSearch(rt.params, domain, database)
|
|
34304
|
+
);
|
|
34305
|
+
break;
|
|
34306
|
+
case "paid_search":
|
|
34307
|
+
sections.push(
|
|
34308
|
+
...await fetchPaidSearch(rt.params, domain, database)
|
|
34309
|
+
);
|
|
34310
|
+
break;
|
|
34311
|
+
case "backlinks":
|
|
34312
|
+
sections.push(...await fetchBacklinks(rt.params, domain));
|
|
34313
|
+
break;
|
|
34314
|
+
}
|
|
33482
34315
|
}
|
|
33483
|
-
|
|
33484
|
-
|
|
33485
|
-
|
|
33486
|
-
|
|
33487
|
-
|
|
33488
|
-
|
|
33489
|
-
|
|
34316
|
+
if (state.projects?.length) {
|
|
34317
|
+
const result = await fetchProjects(rt.params);
|
|
34318
|
+
if (result.ok) {
|
|
34319
|
+
const projectByIdMap = /* @__PURE__ */ new Map();
|
|
34320
|
+
for (const p of result.projects) {
|
|
34321
|
+
const id = projectId(p);
|
|
34322
|
+
if (id) projectByIdMap.set(id, p);
|
|
34323
|
+
}
|
|
34324
|
+
const targetIds = await resolveSetupSelection({
|
|
34325
|
+
selected: state.projects,
|
|
34326
|
+
allSentinel: ALL_PROJECTS6,
|
|
34327
|
+
fetchAll: async () => result.projects.map((p) => projectId(p)).filter((id) => id),
|
|
34328
|
+
limit: SEMRUSH_SETUP_MAX_PROJECTS
|
|
34329
|
+
});
|
|
34330
|
+
if (targetIds.length > 0) {
|
|
34331
|
+
sections.push("### Projects", "");
|
|
34332
|
+
sections.push("| Project | Domain | Created |");
|
|
34333
|
+
sections.push("|---------|--------|---------|");
|
|
34334
|
+
for (const id of targetIds) {
|
|
34335
|
+
const p = projectByIdMap.get(id);
|
|
34336
|
+
if (!p) {
|
|
34337
|
+
sections.push(`| ${id} | - | - |`);
|
|
34338
|
+
continue;
|
|
34339
|
+
}
|
|
34340
|
+
const name = projectName(p).replace(/\|/g, "\\|");
|
|
34341
|
+
const dom = projectDomain(p).replace(/\|/g, "\\|") || "-";
|
|
34342
|
+
const created = projectCreatedAt(p) || "-";
|
|
34343
|
+
sections.push(`| ${name} | ${dom} | ${created} |`);
|
|
34344
|
+
}
|
|
34345
|
+
sections.push("");
|
|
34346
|
+
}
|
|
33490
34347
|
}
|
|
33491
|
-
const name = projectName(p).replace(/\|/g, "\\|");
|
|
33492
|
-
const domain = projectDomain(p).replace(/\|/g, "\\|") || "-";
|
|
33493
|
-
const created = projectCreatedAt(p) || "-";
|
|
33494
|
-
sections.push(`| ${name} | ${domain} | ${created} |`);
|
|
33495
34348
|
}
|
|
33496
|
-
sections.push("");
|
|
33497
34349
|
return sections.join("\n");
|
|
33498
34350
|
}
|
|
33499
34351
|
};
|
|
@@ -33754,7 +34606,7 @@ API \u30E6\u30CB\u30C3\u30C8\u6B8B\u91CF\u306E\u78BA\u8A8D\uFF08\u7121\u6599\u30
|
|
|
33754
34606
|
|
|
33755
34607
|
// ../connectors/src/connectors/google-search-console-oauth/tools/list-sites.ts
|
|
33756
34608
|
import { z as z84 } from "zod";
|
|
33757
|
-
var
|
|
34609
|
+
var BASE_URL60 = "https://searchconsole.googleapis.com/webmasters/v3";
|
|
33758
34610
|
var REQUEST_TIMEOUT_MS67 = 6e4;
|
|
33759
34611
|
var cachedToken30 = null;
|
|
33760
34612
|
async function getProxyToken30(config) {
|
|
@@ -33825,7 +34677,7 @@ var listSitesTool = new ConnectorTool({
|
|
|
33825
34677
|
`[connector-request] google-search-console-oauth/${connection2.name}: listSites`
|
|
33826
34678
|
);
|
|
33827
34679
|
try {
|
|
33828
|
-
const url = `${
|
|
34680
|
+
const url = `${BASE_URL60}/sites`;
|
|
33829
34681
|
const token = await getProxyToken30(config.oauthProxy);
|
|
33830
34682
|
const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
33831
34683
|
const controller = new AbortController();
|
|
@@ -34007,7 +34859,7 @@ var googleSearchConsoleOauthSetupFlow = {
|
|
|
34007
34859
|
import { z as z85 } from "zod";
|
|
34008
34860
|
var BASE_HOST10 = "https://searchconsole.googleapis.com";
|
|
34009
34861
|
var BASE_PATH_SEGMENT10 = "/webmasters/v3";
|
|
34010
|
-
var
|
|
34862
|
+
var BASE_URL61 = `${BASE_HOST10}${BASE_PATH_SEGMENT10}`;
|
|
34011
34863
|
var REQUEST_TIMEOUT_MS68 = 6e4;
|
|
34012
34864
|
var cachedToken31 = null;
|
|
34013
34865
|
async function getProxyToken31(config) {
|
|
@@ -34092,7 +34944,7 @@ For URL Inspection API requests, use the absolute path '/v1/urlInspection/index:
|
|
|
34092
34944
|
resolvedPath,
|
|
34093
34945
|
BASE_PATH_SEGMENT10
|
|
34094
34946
|
);
|
|
34095
|
-
let url = `${
|
|
34947
|
+
let url = `${BASE_URL61}${normalizedPath}`;
|
|
34096
34948
|
if (queryParams) {
|
|
34097
34949
|
const searchParams = new URLSearchParams(queryParams);
|
|
34098
34950
|
url += `?${searchParams.toString()}`;
|
|
@@ -34418,7 +35270,7 @@ function isInternalSchema3(name) {
|
|
|
34418
35270
|
if (lower.startsWith("pg_toast_")) return true;
|
|
34419
35271
|
return false;
|
|
34420
35272
|
}
|
|
34421
|
-
async function
|
|
35273
|
+
async function fetchTableNames4(params, schema) {
|
|
34422
35274
|
const rows = await runQuery10(
|
|
34423
35275
|
params,
|
|
34424
35276
|
`SELECT table_name FROM information_schema.tables
|
|
@@ -34451,17 +35303,17 @@ var supabaseSetupFlow = {
|
|
|
34451
35303
|
slug: "tables",
|
|
34452
35304
|
type: "multiSelect",
|
|
34453
35305
|
question: {
|
|
34454
|
-
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
34455
|
-
en: "Select target tables (multi-select allowed)"
|
|
35306
|
+
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
35307
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
34456
35308
|
},
|
|
34457
35309
|
async fetchOptions(state, rt) {
|
|
34458
35310
|
if (!state.schema) return [];
|
|
34459
|
-
const names = await
|
|
35311
|
+
const names = await fetchTableNames4(rt.params, state.schema);
|
|
34460
35312
|
const tableOptions = names.map((value) => ({ value }));
|
|
34461
35313
|
return [
|
|
34462
35314
|
{
|
|
34463
35315
|
value: ALL_TABLES13,
|
|
34464
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
35316
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
34465
35317
|
},
|
|
34466
35318
|
...tableOptions
|
|
34467
35319
|
];
|
|
@@ -34477,7 +35329,7 @@ var supabaseSetupFlow = {
|
|
|
34477
35329
|
const targetTables = await resolveSetupSelection({
|
|
34478
35330
|
selected: state.tables,
|
|
34479
35331
|
allSentinel: ALL_TABLES13,
|
|
34480
|
-
fetchAll: () =>
|
|
35332
|
+
fetchAll: () => fetchTableNames4(rt.params, schema),
|
|
34481
35333
|
limit: SUPABASE_SETUP_MAX_TABLES
|
|
34482
35334
|
});
|
|
34483
35335
|
const sections = [
|
|
@@ -34712,13 +35564,13 @@ var parameters71 = {
|
|
|
34712
35564
|
};
|
|
34713
35565
|
|
|
34714
35566
|
// ../connectors/src/connectors/clickup/utils.ts
|
|
34715
|
-
var
|
|
35567
|
+
var BASE_URL62 = "https://api.clickup.com/api/v2";
|
|
34716
35568
|
async function apiFetch30(params, path5, init) {
|
|
34717
35569
|
const token = params[parameters71.apiToken.slug];
|
|
34718
35570
|
if (!token) {
|
|
34719
35571
|
throw new Error("clickup: missing required parameter: api-token");
|
|
34720
35572
|
}
|
|
34721
|
-
const url = `${
|
|
35573
|
+
const url = `${BASE_URL62}${path5.startsWith("/") ? "" : "/"}${path5}`;
|
|
34722
35574
|
const headers = new Headers(init?.headers);
|
|
34723
35575
|
headers.set("Authorization", token);
|
|
34724
35576
|
if (!headers.has("Accept")) headers.set("Accept", "application/json");
|
|
@@ -34846,7 +35698,7 @@ var clickupSetupFlow = {
|
|
|
34846
35698
|
import { z as z87 } from "zod";
|
|
34847
35699
|
var BASE_HOST11 = "https://api.clickup.com";
|
|
34848
35700
|
var BASE_PATH_SEGMENT11 = "/api/v2";
|
|
34849
|
-
var
|
|
35701
|
+
var BASE_URL63 = `${BASE_HOST11}${BASE_PATH_SEGMENT11}`;
|
|
34850
35702
|
var REQUEST_TIMEOUT_MS69 = 6e4;
|
|
34851
35703
|
var inputSchema87 = z87.object({
|
|
34852
35704
|
toolUseIntent: z87.string().optional().describe(
|
|
@@ -34919,7 +35771,7 @@ Pagination: ClickUp uses zero-indexed \`page\` query parameter on list endpoints
|
|
|
34919
35771
|
try {
|
|
34920
35772
|
const token = parameters71.apiToken.getValue(connection2);
|
|
34921
35773
|
const normalizedPath = normalizeRequestPath(path5, BASE_PATH_SEGMENT11);
|
|
34922
|
-
const url = `${
|
|
35774
|
+
const url = `${BASE_URL63}${normalizedPath}`;
|
|
34923
35775
|
const controller = new AbortController();
|
|
34924
35776
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS69);
|
|
34925
35777
|
try {
|
|
@@ -35249,7 +36101,7 @@ function quoteLiteral4(value) {
|
|
|
35249
36101
|
}
|
|
35250
36102
|
function buildFlow(options) {
|
|
35251
36103
|
const { connectorName, forceEncrypt } = options;
|
|
35252
|
-
async function
|
|
36104
|
+
async function fetchTableNames5(params, schema) {
|
|
35253
36105
|
const rows = await runSqlServerSetupQuery(
|
|
35254
36106
|
params,
|
|
35255
36107
|
`SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
|
|
@@ -35284,17 +36136,17 @@ function buildFlow(options) {
|
|
|
35284
36136
|
slug: "tables",
|
|
35285
36137
|
type: "multiSelect",
|
|
35286
36138
|
question: {
|
|
35287
|
-
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
35288
|
-
en: "Select target tables (multi-select allowed)"
|
|
36139
|
+
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
36140
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
35289
36141
|
},
|
|
35290
36142
|
async fetchOptions(state, rt) {
|
|
35291
36143
|
if (!state.schema) return [];
|
|
35292
|
-
const names = await
|
|
36144
|
+
const names = await fetchTableNames5(rt.params, state.schema);
|
|
35293
36145
|
const tableOptions = names.map((value) => ({ value }));
|
|
35294
36146
|
return [
|
|
35295
36147
|
{
|
|
35296
36148
|
value: ALL_TABLES14,
|
|
35297
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
36149
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
35298
36150
|
},
|
|
35299
36151
|
...tableOptions
|
|
35300
36152
|
];
|
|
@@ -35310,7 +36162,7 @@ function buildFlow(options) {
|
|
|
35310
36162
|
const targetTables = await resolveSetupSelection({
|
|
35311
36163
|
selected: state.tables,
|
|
35312
36164
|
allSentinel: ALL_TABLES14,
|
|
35313
|
-
fetchAll: () =>
|
|
36165
|
+
fetchAll: () => fetchTableNames5(rt.params, schema),
|
|
35314
36166
|
limit: SQLSERVER_SETUP_MAX_TABLES
|
|
35315
36167
|
});
|
|
35316
36168
|
const sections = [
|
|
@@ -36305,14 +37157,15 @@ function isInternalOwner(name) {
|
|
|
36305
37157
|
function quoteLiteral5(value) {
|
|
36306
37158
|
return "'" + value.replace(/'/g, "''") + "'";
|
|
36307
37159
|
}
|
|
36308
|
-
async function
|
|
37160
|
+
async function fetchTableAndViewNames2(params, owner) {
|
|
36309
37161
|
const rows = await runOracleSetupQuery(
|
|
36310
37162
|
params,
|
|
36311
|
-
`SELECT TABLE_NAME FROM ALL_TABLES
|
|
36312
|
-
|
|
36313
|
-
|
|
37163
|
+
`SELECT TABLE_NAME FROM ALL_TABLES WHERE OWNER = ${quoteLiteral5(owner)}
|
|
37164
|
+
UNION
|
|
37165
|
+
SELECT VIEW_NAME FROM ALL_VIEWS WHERE OWNER = ${quoteLiteral5(owner)}
|
|
37166
|
+
ORDER BY 1`
|
|
36314
37167
|
);
|
|
36315
|
-
return rows.map((r) => String(r["TABLE_NAME"] ?? "")).filter((name) => name);
|
|
37168
|
+
return rows.map((r) => String(r["TABLE_NAME"] ?? r["VIEW_NAME"] ?? "")).filter((name) => name);
|
|
36316
37169
|
}
|
|
36317
37170
|
var oracleSetupFlow = {
|
|
36318
37171
|
initialState: () => ({}),
|
|
@@ -36337,17 +37190,17 @@ var oracleSetupFlow = {
|
|
|
36337
37190
|
slug: "tables",
|
|
36338
37191
|
type: "multiSelect",
|
|
36339
37192
|
question: {
|
|
36340
|
-
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
36341
|
-
en: "Select target tables (multi-select allowed)"
|
|
37193
|
+
ja: "\u5BFE\u8C61\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
37194
|
+
en: "Select target tables and views (multi-select allowed)"
|
|
36342
37195
|
},
|
|
36343
37196
|
async fetchOptions(state, rt) {
|
|
36344
37197
|
if (!state.owner) return [];
|
|
36345
|
-
const names = await
|
|
37198
|
+
const names = await fetchTableAndViewNames2(rt.params, state.owner);
|
|
36346
37199
|
const tableOptions = names.map((value) => ({ value }));
|
|
36347
37200
|
return [
|
|
36348
37201
|
{
|
|
36349
37202
|
value: ALL_TABLES15,
|
|
36350
|
-
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB" : "All tables"
|
|
37203
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30C6\u30FC\u30D6\u30EB\u30FB\u30D3\u30E5\u30FC" : "All tables and views"
|
|
36351
37204
|
},
|
|
36352
37205
|
...tableOptions
|
|
36353
37206
|
];
|
|
@@ -36363,9 +37216,22 @@ var oracleSetupFlow = {
|
|
|
36363
37216
|
const targetTables = await resolveSetupSelection({
|
|
36364
37217
|
selected: state.tables,
|
|
36365
37218
|
allSentinel: ALL_TABLES15,
|
|
36366
|
-
fetchAll: () =>
|
|
37219
|
+
fetchAll: () => fetchTableAndViewNames2(rt.params, owner),
|
|
36367
37220
|
limit: ORACLE_SETUP_MAX_TABLES
|
|
36368
37221
|
});
|
|
37222
|
+
const typeRows = targetTables.length > 0 ? await runOracleSetupQuery(
|
|
37223
|
+
rt.params,
|
|
37224
|
+
`SELECT OBJECT_NAME, OBJECT_TYPE FROM ALL_OBJECTS
|
|
37225
|
+
WHERE OWNER = ${quoteLiteral5(owner)}
|
|
37226
|
+
AND OBJECT_NAME IN (${targetTables.map(quoteLiteral5).join(", ")})
|
|
37227
|
+
AND OBJECT_TYPE IN ('TABLE', 'VIEW')`
|
|
37228
|
+
) : [];
|
|
37229
|
+
const typeMap = new Map(
|
|
37230
|
+
typeRows.map((r) => [
|
|
37231
|
+
String(r["OBJECT_NAME"] ?? ""),
|
|
37232
|
+
String(r["OBJECT_TYPE"] ?? "TABLE")
|
|
37233
|
+
])
|
|
37234
|
+
);
|
|
36369
37235
|
const sections = [
|
|
36370
37236
|
"## Oracle Database",
|
|
36371
37237
|
"",
|
|
@@ -36373,6 +37239,7 @@ var oracleSetupFlow = {
|
|
|
36373
37239
|
""
|
|
36374
37240
|
];
|
|
36375
37241
|
for (const table of targetTables) {
|
|
37242
|
+
const heading = typeMap.get(table) === "VIEW" ? "View" : "Table";
|
|
36376
37243
|
const cols = await runOracleSetupQuery(
|
|
36377
37244
|
rt.params,
|
|
36378
37245
|
`SELECT COLUMN_NAME, DATA_TYPE, NULLABLE, DATA_DEFAULT
|
|
@@ -36381,7 +37248,7 @@ var oracleSetupFlow = {
|
|
|
36381
37248
|
AND TABLE_NAME = ${quoteLiteral5(table)}
|
|
36382
37249
|
ORDER BY COLUMN_ID`
|
|
36383
37250
|
);
|
|
36384
|
-
sections.push(`####
|
|
37251
|
+
sections.push(`#### ${heading}: ${table}`, "");
|
|
36385
37252
|
sections.push("| Column | Type | Nullable | Default |");
|
|
36386
37253
|
sections.push("|--------|------|----------|---------|");
|
|
36387
37254
|
for (const c of cols) {
|
|
@@ -38686,7 +39553,7 @@ export default async function handler(c: Context) {
|
|
|
38686
39553
|
import { z as z97 } from "zod";
|
|
38687
39554
|
var BASE_HOST12 = "https://api.powerbi.com";
|
|
38688
39555
|
var BASE_PATH_SEGMENT18 = "/v1.0/myorg";
|
|
38689
|
-
var
|
|
39556
|
+
var BASE_URL64 = `${BASE_HOST12}${BASE_PATH_SEGMENT18}`;
|
|
38690
39557
|
var REQUEST_TIMEOUT_MS74 = 6e4;
|
|
38691
39558
|
var cachedToken32 = null;
|
|
38692
39559
|
async function getProxyToken32(config) {
|
|
@@ -38768,7 +39635,7 @@ The signed-in user must have access to the workspace; unlike Service Principals,
|
|
|
38768
39635
|
);
|
|
38769
39636
|
try {
|
|
38770
39637
|
const normalizedPath = normalizeRequestPath(path5, BASE_PATH_SEGMENT18);
|
|
38771
|
-
let url = `${
|
|
39638
|
+
let url = `${BASE_URL64}${normalizedPath}`;
|
|
38772
39639
|
if (queryParams) {
|
|
38773
39640
|
const searchParams = new URLSearchParams(queryParams);
|
|
38774
39641
|
url += `?${searchParams.toString()}`;
|
|
@@ -38851,14 +39718,18 @@ var powerbiOauthOnboarding = new ConnectorOnboarding({
|
|
|
38851
39718
|
var parameters80 = {};
|
|
38852
39719
|
|
|
38853
39720
|
// ../connectors/src/connectors/powerbi-oauth/utils.ts
|
|
38854
|
-
var
|
|
39721
|
+
var BASE_URL65 = "https://api.powerbi.com/v1.0/myorg";
|
|
38855
39722
|
function apiFetch35(proxyFetch, path5, init) {
|
|
38856
|
-
const url = `${
|
|
39723
|
+
const url = `${BASE_URL65}${path5.startsWith("/") ? "" : "/"}${path5}`;
|
|
38857
39724
|
return proxyFetch(url, init);
|
|
38858
39725
|
}
|
|
38859
39726
|
|
|
38860
39727
|
// ../connectors/src/connectors/powerbi-oauth/setup-flow.ts
|
|
38861
39728
|
var ALL_WORKSPACES = "__ALL_WORKSPACES__";
|
|
39729
|
+
var MY_WORKSPACE = "__MY_WORKSPACE__";
|
|
39730
|
+
var ALL_DATASETS = "__ALL_DATASETS__";
|
|
39731
|
+
var ALL_REPORTS = "__ALL_REPORTS__";
|
|
39732
|
+
var ALL_DASHBOARDS = "__ALL_DASHBOARDS__";
|
|
38862
39733
|
var POWERBI_SETUP_MAX_WORKSPACES = 10;
|
|
38863
39734
|
var RESOURCE_DISPLAY_LIMIT = 25;
|
|
38864
39735
|
var RESOURCE_DATASETS = "datasets";
|
|
@@ -38874,14 +39745,12 @@ async function listGroups(proxyFetch) {
|
|
|
38874
39745
|
return data.value ?? [];
|
|
38875
39746
|
}
|
|
38876
39747
|
async function listResource(proxyFetch, groupId, resource) {
|
|
38877
|
-
const
|
|
38878
|
-
|
|
38879
|
-
`/groups/${encodeURIComponent(groupId)}/${resource}`
|
|
38880
|
-
);
|
|
39748
|
+
const path5 = groupId === MY_WORKSPACE ? `/${resource}` : `/groups/${encodeURIComponent(groupId)}/${resource}`;
|
|
39749
|
+
const res = await apiFetch35(proxyFetch, path5);
|
|
38881
39750
|
if (!res.ok) {
|
|
38882
39751
|
const body = await res.text().catch(() => res.statusText);
|
|
38883
39752
|
throw new Error(
|
|
38884
|
-
`powerbi: list ${resource} for group ${groupId} failed (${res.status}): ${body}`
|
|
39753
|
+
`powerbi: list ${resource} for ${groupId === MY_WORKSPACE ? "My workspace" : `group ${groupId}`} failed (${res.status}): ${body}`
|
|
38885
39754
|
);
|
|
38886
39755
|
}
|
|
38887
39756
|
const data = await res.json();
|
|
@@ -38890,6 +39759,99 @@ async function listResource(proxyFetch, groupId, resource) {
|
|
|
38890
39759
|
function resourceLabel(r) {
|
|
38891
39760
|
return r.name ?? r.displayName ?? r.id ?? "(unknown)";
|
|
38892
39761
|
}
|
|
39762
|
+
var INTERNAL_TABLE_PREFIXES = [
|
|
39763
|
+
"DateTableTemplate_",
|
|
39764
|
+
"LocalDateTable_"
|
|
39765
|
+
];
|
|
39766
|
+
function isInternalColumn(name) {
|
|
39767
|
+
return /^RowNumber-[0-9A-Fa-f-]+$/.test(name);
|
|
39768
|
+
}
|
|
39769
|
+
async function fetchDatasetSchema(proxyFetch, wsId, datasetId) {
|
|
39770
|
+
const pathPrefix = wsId === MY_WORKSPACE ? "" : `/groups/${encodeURIComponent(wsId)}`;
|
|
39771
|
+
const daxQuery = 'EVALUATE SELECTCOLUMNS(COLUMNSTATISTICS(), "T", [Table Name], "C", [Column Name])';
|
|
39772
|
+
const res = await apiFetch35(
|
|
39773
|
+
proxyFetch,
|
|
39774
|
+
`${pathPrefix}/datasets/${encodeURIComponent(datasetId)}/executeQueries`,
|
|
39775
|
+
{
|
|
39776
|
+
method: "POST",
|
|
39777
|
+
headers: { "Content-Type": "application/json" },
|
|
39778
|
+
body: JSON.stringify({
|
|
39779
|
+
queries: [{ query: daxQuery }],
|
|
39780
|
+
serializerSettings: { includeNulls: true }
|
|
39781
|
+
})
|
|
39782
|
+
}
|
|
39783
|
+
);
|
|
39784
|
+
if (!res.ok) return /* @__PURE__ */ new Map();
|
|
39785
|
+
const data = await res.json();
|
|
39786
|
+
const rows = data.results?.[0]?.tables?.[0]?.rows ?? [];
|
|
39787
|
+
const schema = /* @__PURE__ */ new Map();
|
|
39788
|
+
for (const row of rows) {
|
|
39789
|
+
const table = row["[T]"] ?? "";
|
|
39790
|
+
const column = row["[C]"] ?? "";
|
|
39791
|
+
if (!table || !column) continue;
|
|
39792
|
+
if (INTERNAL_TABLE_PREFIXES.some((p) => table.startsWith(p))) continue;
|
|
39793
|
+
if (isInternalColumn(column)) continue;
|
|
39794
|
+
if (!schema.has(table)) schema.set(table, []);
|
|
39795
|
+
schema.get(table).push(column);
|
|
39796
|
+
}
|
|
39797
|
+
return schema;
|
|
39798
|
+
}
|
|
39799
|
+
function workspaceName(wsId, groupById, language) {
|
|
39800
|
+
if (wsId === MY_WORKSPACE) {
|
|
39801
|
+
return language === "ja" ? "\u30DE\u30A4 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9" : "My workspace";
|
|
39802
|
+
}
|
|
39803
|
+
return groupById.get(wsId)?.name ?? wsId;
|
|
39804
|
+
}
|
|
39805
|
+
async function resolveWorkspaceIds(selected, proxyFetch) {
|
|
39806
|
+
return resolveSetupSelection({
|
|
39807
|
+
selected,
|
|
39808
|
+
allSentinel: ALL_WORKSPACES,
|
|
39809
|
+
fetchAll: async () => {
|
|
39810
|
+
const groups = await listGroups(proxyFetch);
|
|
39811
|
+
return [MY_WORKSPACE, ...groups.map((g) => g.id).filter(Boolean)];
|
|
39812
|
+
},
|
|
39813
|
+
limit: POWERBI_SETUP_MAX_WORKSPACES
|
|
39814
|
+
});
|
|
39815
|
+
}
|
|
39816
|
+
function compoundKey(wsId, objectId) {
|
|
39817
|
+
return `${wsId}:${objectId}`;
|
|
39818
|
+
}
|
|
39819
|
+
function parseCompoundKey(key) {
|
|
39820
|
+
const idx = key.indexOf(":");
|
|
39821
|
+
if (idx < 0) return { wsId: "", objectId: key };
|
|
39822
|
+
return { wsId: key.slice(0, idx), objectId: key.slice(idx + 1) };
|
|
39823
|
+
}
|
|
39824
|
+
async function fetchObjectOptions(state, resource, allSentinel, allLabelJa, allLabelEn, rt) {
|
|
39825
|
+
if (!state.workspaces?.length || !state.resources?.includes(resource))
|
|
39826
|
+
return [];
|
|
39827
|
+
const wsIds = await resolveWorkspaceIds(
|
|
39828
|
+
state.workspaces,
|
|
39829
|
+
rt.config.proxyFetch
|
|
39830
|
+
);
|
|
39831
|
+
const allGroups = await listGroups(rt.config.proxyFetch);
|
|
39832
|
+
const groupById = new Map(allGroups.map((g) => [g.id, g]));
|
|
39833
|
+
const multiWorkspace = wsIds.length > 1;
|
|
39834
|
+
const options = [];
|
|
39835
|
+
for (const wsId of wsIds) {
|
|
39836
|
+
const wsLabel = workspaceName(wsId, groupById, rt.language);
|
|
39837
|
+
const items = await listResource(rt.config.proxyFetch, wsId, resource);
|
|
39838
|
+
for (const item of items) {
|
|
39839
|
+
if (!item.id) continue;
|
|
39840
|
+
options.push({
|
|
39841
|
+
value: compoundKey(wsId, item.id),
|
|
39842
|
+
label: multiWorkspace ? `${wsLabel} / ${resourceLabel(item)}` : resourceLabel(item)
|
|
39843
|
+
});
|
|
39844
|
+
}
|
|
39845
|
+
}
|
|
39846
|
+
if (options.length === 0) return [];
|
|
39847
|
+
return [
|
|
39848
|
+
{
|
|
39849
|
+
value: allSentinel,
|
|
39850
|
+
label: rt.language === "ja" ? allLabelJa : allLabelEn
|
|
39851
|
+
},
|
|
39852
|
+
...options
|
|
39853
|
+
];
|
|
39854
|
+
}
|
|
38893
39855
|
var powerbiOauthSetupFlow = {
|
|
38894
39856
|
initialState: () => ({}),
|
|
38895
39857
|
steps: [
|
|
@@ -38908,6 +39870,10 @@ var powerbiOauthSetupFlow = {
|
|
|
38908
39870
|
value: ALL_WORKSPACES,
|
|
38909
39871
|
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9" : "All workspaces"
|
|
38910
39872
|
},
|
|
39873
|
+
{
|
|
39874
|
+
value: MY_WORKSPACE,
|
|
39875
|
+
label: rt.language === "ja" ? "\u30DE\u30A4 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9" : "My workspace"
|
|
39876
|
+
},
|
|
38911
39877
|
...options
|
|
38912
39878
|
];
|
|
38913
39879
|
},
|
|
@@ -38922,16 +39888,82 @@ var powerbiOauthSetupFlow = {
|
|
|
38922
39888
|
},
|
|
38923
39889
|
async fetchOptions(state, rt) {
|
|
38924
39890
|
if (!state.workspaces?.length) return [];
|
|
38925
|
-
const datasetsLabel = rt.language === "ja" ? "\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8" : "Datasets";
|
|
38926
|
-
const reportsLabel = rt.language === "ja" ? "\u30EC\u30DD\u30FC\u30C8" : "Reports";
|
|
38927
|
-
const dashboardsLabel = rt.language === "ja" ? "\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9" : "Dashboards";
|
|
38928
39891
|
return [
|
|
38929
|
-
{
|
|
38930
|
-
|
|
38931
|
-
|
|
39892
|
+
{
|
|
39893
|
+
value: RESOURCE_DATASETS,
|
|
39894
|
+
label: rt.language === "ja" ? "\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8" : "Datasets"
|
|
39895
|
+
},
|
|
39896
|
+
{
|
|
39897
|
+
value: RESOURCE_REPORTS,
|
|
39898
|
+
label: rt.language === "ja" ? "\u30EC\u30DD\u30FC\u30C8" : "Reports"
|
|
39899
|
+
},
|
|
39900
|
+
{
|
|
39901
|
+
value: RESOURCE_DASHBOARDS,
|
|
39902
|
+
label: rt.language === "ja" ? "\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9" : "Dashboards"
|
|
39903
|
+
}
|
|
38932
39904
|
];
|
|
38933
39905
|
},
|
|
38934
39906
|
applyAnswer: (state, answer) => ({ ...state, resources: answer })
|
|
39907
|
+
},
|
|
39908
|
+
{
|
|
39909
|
+
slug: "datasets",
|
|
39910
|
+
type: "multiSelect",
|
|
39911
|
+
question: {
|
|
39912
|
+
ja: "\u4F7F\u7528\u3059\u308B\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
39913
|
+
en: "Select the datasets you want to use (multi-select allowed)"
|
|
39914
|
+
},
|
|
39915
|
+
async fetchOptions(state, rt) {
|
|
39916
|
+
return fetchObjectOptions(
|
|
39917
|
+
state,
|
|
39918
|
+
RESOURCE_DATASETS,
|
|
39919
|
+
ALL_DATASETS,
|
|
39920
|
+
"\u3059\u3079\u3066\u306E\u30C7\u30FC\u30BF\u30BB\u30C3\u30C8",
|
|
39921
|
+
"All datasets",
|
|
39922
|
+
rt
|
|
39923
|
+
);
|
|
39924
|
+
},
|
|
39925
|
+
applyAnswer: (state, answer) => ({ ...state, selectedDatasets: answer })
|
|
39926
|
+
},
|
|
39927
|
+
{
|
|
39928
|
+
slug: "reports",
|
|
39929
|
+
type: "multiSelect",
|
|
39930
|
+
question: {
|
|
39931
|
+
ja: "\u4F7F\u7528\u3059\u308B\u30EC\u30DD\u30FC\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
39932
|
+
en: "Select the reports you want to use (multi-select allowed)"
|
|
39933
|
+
},
|
|
39934
|
+
async fetchOptions(state, rt) {
|
|
39935
|
+
return fetchObjectOptions(
|
|
39936
|
+
state,
|
|
39937
|
+
RESOURCE_REPORTS,
|
|
39938
|
+
ALL_REPORTS,
|
|
39939
|
+
"\u3059\u3079\u3066\u306E\u30EC\u30DD\u30FC\u30C8",
|
|
39940
|
+
"All reports",
|
|
39941
|
+
rt
|
|
39942
|
+
);
|
|
39943
|
+
},
|
|
39944
|
+
applyAnswer: (state, answer) => ({ ...state, selectedReports: answer })
|
|
39945
|
+
},
|
|
39946
|
+
{
|
|
39947
|
+
slug: "dashboards",
|
|
39948
|
+
type: "multiSelect",
|
|
39949
|
+
question: {
|
|
39950
|
+
ja: "\u4F7F\u7528\u3059\u308B\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
39951
|
+
en: "Select the dashboards you want to use (multi-select allowed)"
|
|
39952
|
+
},
|
|
39953
|
+
async fetchOptions(state, rt) {
|
|
39954
|
+
return fetchObjectOptions(
|
|
39955
|
+
state,
|
|
39956
|
+
RESOURCE_DASHBOARDS,
|
|
39957
|
+
ALL_DASHBOARDS,
|
|
39958
|
+
"\u3059\u3079\u3066\u306E\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9",
|
|
39959
|
+
"All dashboards",
|
|
39960
|
+
rt
|
|
39961
|
+
);
|
|
39962
|
+
},
|
|
39963
|
+
applyAnswer: (state, answer) => ({
|
|
39964
|
+
...state,
|
|
39965
|
+
selectedDashboards: answer
|
|
39966
|
+
})
|
|
38935
39967
|
}
|
|
38936
39968
|
],
|
|
38937
39969
|
async finalize(state, rt) {
|
|
@@ -38940,37 +39972,119 @@ var powerbiOauthSetupFlow = {
|
|
|
38940
39972
|
}
|
|
38941
39973
|
const allGroups = await listGroups(rt.config.proxyFetch);
|
|
38942
39974
|
const groupById = new Map(allGroups.map((g) => [g.id, g]));
|
|
38943
|
-
const
|
|
38944
|
-
|
|
38945
|
-
|
|
38946
|
-
|
|
38947
|
-
limit: POWERBI_SETUP_MAX_WORKSPACES
|
|
38948
|
-
});
|
|
39975
|
+
const wsIds = await resolveWorkspaceIds(
|
|
39976
|
+
state.workspaces,
|
|
39977
|
+
rt.config.proxyFetch
|
|
39978
|
+
);
|
|
38949
39979
|
const selectedResources = new Set(state.resources);
|
|
39980
|
+
async function resolveObjects(selected, allSentinel, resource) {
|
|
39981
|
+
const byWorkspace = /* @__PURE__ */ new Map();
|
|
39982
|
+
if (!selected || !selectedResources.has(resource)) return byWorkspace;
|
|
39983
|
+
if (selected.includes(allSentinel)) {
|
|
39984
|
+
for (const wsId of wsIds) {
|
|
39985
|
+
const items = await listResource(
|
|
39986
|
+
rt.config.proxyFetch,
|
|
39987
|
+
wsId,
|
|
39988
|
+
resource
|
|
39989
|
+
);
|
|
39990
|
+
const ids = items.map((i) => i.id).filter((id) => !!id);
|
|
39991
|
+
if (ids.length > 0) byWorkspace.set(wsId, new Set(ids));
|
|
39992
|
+
}
|
|
39993
|
+
} else {
|
|
39994
|
+
for (const key of selected) {
|
|
39995
|
+
if (key === allSentinel) continue;
|
|
39996
|
+
const { wsId, objectId } = parseCompoundKey(key);
|
|
39997
|
+
if (!byWorkspace.has(wsId)) byWorkspace.set(wsId, /* @__PURE__ */ new Set());
|
|
39998
|
+
byWorkspace.get(wsId).add(objectId);
|
|
39999
|
+
}
|
|
40000
|
+
}
|
|
40001
|
+
return byWorkspace;
|
|
40002
|
+
}
|
|
40003
|
+
const datasetsByWs = await resolveObjects(
|
|
40004
|
+
state.selectedDatasets,
|
|
40005
|
+
ALL_DATASETS,
|
|
40006
|
+
RESOURCE_DATASETS
|
|
40007
|
+
);
|
|
40008
|
+
const reportsByWs = await resolveObjects(
|
|
40009
|
+
state.selectedReports,
|
|
40010
|
+
ALL_REPORTS,
|
|
40011
|
+
RESOURCE_REPORTS
|
|
40012
|
+
);
|
|
40013
|
+
const dashboardsByWs = await resolveObjects(
|
|
40014
|
+
state.selectedDashboards,
|
|
40015
|
+
ALL_DASHBOARDS,
|
|
40016
|
+
RESOURCE_DASHBOARDS
|
|
40017
|
+
);
|
|
40018
|
+
const allWsIds = /* @__PURE__ */ new Set([
|
|
40019
|
+
...datasetsByWs.keys(),
|
|
40020
|
+
...reportsByWs.keys(),
|
|
40021
|
+
...dashboardsByWs.keys()
|
|
40022
|
+
]);
|
|
38950
40023
|
const sections = ["## Power BI", ""];
|
|
38951
|
-
if (
|
|
38952
|
-
sections.push("_No
|
|
40024
|
+
if (allWsIds.size === 0) {
|
|
40025
|
+
sections.push("_No resources selected._", "");
|
|
38953
40026
|
return sections.join("\n");
|
|
38954
40027
|
}
|
|
38955
|
-
for (const
|
|
38956
|
-
|
|
38957
|
-
const name =
|
|
38958
|
-
sections.push(`### Workspace: ${name}`, ""
|
|
38959
|
-
|
|
38960
|
-
|
|
38961
|
-
|
|
38962
|
-
|
|
40028
|
+
for (const wsId of wsIds) {
|
|
40029
|
+
if (!allWsIds.has(wsId)) continue;
|
|
40030
|
+
const name = workspaceName(wsId, groupById, rt.language);
|
|
40031
|
+
sections.push(`### Workspace: ${name}`, "");
|
|
40032
|
+
if (wsId !== MY_WORKSPACE) {
|
|
40033
|
+
sections.push(`- id: \`${wsId}\``);
|
|
40034
|
+
}
|
|
40035
|
+
const datasetIds = datasetsByWs.get(wsId);
|
|
40036
|
+
if (datasetIds?.size) {
|
|
40037
|
+
const items = await listResource(
|
|
40038
|
+
rt.config.proxyFetch,
|
|
40039
|
+
wsId,
|
|
40040
|
+
RESOURCE_DATASETS
|
|
40041
|
+
);
|
|
40042
|
+
const filtered = items.filter(
|
|
40043
|
+
(item) => item.id && datasetIds.has(item.id)
|
|
40044
|
+
);
|
|
40045
|
+
for (const item of filtered.slice(0, RESOURCE_DISPLAY_LIMIT)) {
|
|
40046
|
+
sections.push(`#### Dataset: ${resourceLabel(item)}`, "");
|
|
40047
|
+
const schema = await fetchDatasetSchema(
|
|
40048
|
+
rt.config.proxyFetch,
|
|
40049
|
+
wsId,
|
|
40050
|
+
item.id
|
|
40051
|
+
);
|
|
40052
|
+
if (schema.size > 0) {
|
|
40053
|
+
for (const [table, columns] of schema) {
|
|
40054
|
+
sections.push(`##### Table: ${table}`, "");
|
|
40055
|
+
sections.push("| Column |");
|
|
40056
|
+
sections.push("|--------|");
|
|
40057
|
+
for (const col of columns) {
|
|
40058
|
+
sections.push(`| ${col} |`);
|
|
40059
|
+
}
|
|
40060
|
+
sections.push("");
|
|
40061
|
+
}
|
|
40062
|
+
} else {
|
|
40063
|
+
sections.push("_Schema not available._", "");
|
|
40064
|
+
}
|
|
40065
|
+
}
|
|
40066
|
+
}
|
|
40067
|
+
for (const [resource, selectedByWs, heading] of [
|
|
40068
|
+
[RESOURCE_REPORTS, reportsByWs, "Reports"],
|
|
40069
|
+
[RESOURCE_DASHBOARDS, dashboardsByWs, "Dashboards"]
|
|
38963
40070
|
]) {
|
|
38964
|
-
|
|
38965
|
-
|
|
38966
|
-
const
|
|
38967
|
-
|
|
38968
|
-
|
|
40071
|
+
const selectedIds = selectedByWs.get(wsId);
|
|
40072
|
+
if (!selectedIds?.size) continue;
|
|
40073
|
+
const items = await listResource(
|
|
40074
|
+
rt.config.proxyFetch,
|
|
40075
|
+
wsId,
|
|
40076
|
+
resource
|
|
40077
|
+
);
|
|
40078
|
+
const filtered = items.filter(
|
|
40079
|
+
(item) => item.id && selectedIds.has(item.id)
|
|
40080
|
+
);
|
|
40081
|
+
sections.push(`- ${heading} (${filtered.length}):`);
|
|
40082
|
+
for (const item of filtered.slice(0, RESOURCE_DISPLAY_LIMIT)) {
|
|
38969
40083
|
sections.push(` - ${resourceLabel(item)}`);
|
|
38970
40084
|
}
|
|
38971
|
-
if (
|
|
40085
|
+
if (filtered.length > RESOURCE_DISPLAY_LIMIT) {
|
|
38972
40086
|
sections.push(
|
|
38973
|
-
` - \u2026and ${
|
|
40087
|
+
` - \u2026and ${filtered.length - RESOURCE_DISPLAY_LIMIT} more`
|
|
38974
40088
|
);
|
|
38975
40089
|
}
|
|
38976
40090
|
}
|
|
@@ -39241,7 +40355,11 @@ async function tableauProxyApiFetch(proxyFetch, params, path5, init) {
|
|
|
39241
40355
|
|
|
39242
40356
|
// ../connectors/src/connectors/tableau/setup-flow.ts
|
|
39243
40357
|
var ALL_PROJECTS7 = "__ALL_PROJECTS__";
|
|
40358
|
+
var ALL_WORKBOOKS = "__ALL_WORKBOOKS__";
|
|
39244
40359
|
var TABLEAU_SETUP_MAX_PROJECTS = 10;
|
|
40360
|
+
var MAX_WORKBOOKS_DETAIL = 10;
|
|
40361
|
+
var MAX_VIEWS_PER_WORKBOOK = 5;
|
|
40362
|
+
var MAX_SAMPLE_ROWS = 5;
|
|
39245
40363
|
var PAGE_SIZE2 = 100;
|
|
39246
40364
|
async function listAllProjects3(rt) {
|
|
39247
40365
|
const all = [];
|
|
@@ -39290,6 +40408,57 @@ async function listProjectResources(rt, resource) {
|
|
|
39290
40408
|
}
|
|
39291
40409
|
return all;
|
|
39292
40410
|
}
|
|
40411
|
+
async function listViewsForWorkbook(rt, workbookId) {
|
|
40412
|
+
const res = await tableauProxyApiFetch(
|
|
40413
|
+
rt.config.proxyFetch,
|
|
40414
|
+
rt.params,
|
|
40415
|
+
`/sites/{siteId}/workbooks/${encodeURIComponent(workbookId)}/views`
|
|
40416
|
+
);
|
|
40417
|
+
if (!res.ok) return [];
|
|
40418
|
+
const data = await res.json();
|
|
40419
|
+
return data.views?.view ?? [];
|
|
40420
|
+
}
|
|
40421
|
+
async function fetchViewDataSample(rt, viewId) {
|
|
40422
|
+
try {
|
|
40423
|
+
const res = await tableauProxyApiFetch(
|
|
40424
|
+
rt.config.proxyFetch,
|
|
40425
|
+
rt.params,
|
|
40426
|
+
`/sites/{siteId}/views/${encodeURIComponent(viewId)}/data`
|
|
40427
|
+
);
|
|
40428
|
+
if (!res.ok) return null;
|
|
40429
|
+
const csv = await res.text();
|
|
40430
|
+
const lines = csv.trim().split("\n").filter(Boolean);
|
|
40431
|
+
if (lines.length === 0) return null;
|
|
40432
|
+
const columns = parseCsvLine(lines[0]);
|
|
40433
|
+
const rows = lines.slice(1, 1 + MAX_SAMPLE_ROWS).map(parseCsvLine);
|
|
40434
|
+
return { columns, rows };
|
|
40435
|
+
} catch {
|
|
40436
|
+
return null;
|
|
40437
|
+
}
|
|
40438
|
+
}
|
|
40439
|
+
function parseCsvLine(line) {
|
|
40440
|
+
const result = [];
|
|
40441
|
+
let current = "";
|
|
40442
|
+
let inQuotes = false;
|
|
40443
|
+
for (let i = 0; i < line.length; i++) {
|
|
40444
|
+
const ch = line[i];
|
|
40445
|
+
if (ch === '"') {
|
|
40446
|
+
if (inQuotes && line[i + 1] === '"') {
|
|
40447
|
+
current += '"';
|
|
40448
|
+
i++;
|
|
40449
|
+
} else {
|
|
40450
|
+
inQuotes = !inQuotes;
|
|
40451
|
+
}
|
|
40452
|
+
} else if (ch === "," && !inQuotes) {
|
|
40453
|
+
result.push(current.trim());
|
|
40454
|
+
current = "";
|
|
40455
|
+
} else {
|
|
40456
|
+
current += ch;
|
|
40457
|
+
}
|
|
40458
|
+
}
|
|
40459
|
+
result.push(current.trim());
|
|
40460
|
+
return result;
|
|
40461
|
+
}
|
|
39293
40462
|
var tableauSetupFlow = {
|
|
39294
40463
|
initialState: () => ({}),
|
|
39295
40464
|
steps: [
|
|
@@ -39312,6 +40481,39 @@ var tableauSetupFlow = {
|
|
|
39312
40481
|
];
|
|
39313
40482
|
},
|
|
39314
40483
|
applyAnswer: (state, answer) => ({ ...state, projects: answer })
|
|
40484
|
+
},
|
|
40485
|
+
{
|
|
40486
|
+
slug: "workbooks",
|
|
40487
|
+
type: "multiSelect",
|
|
40488
|
+
question: {
|
|
40489
|
+
ja: "\u5206\u6790\u5BFE\u8C61\u306E\u30EF\u30FC\u30AF\u30D6\u30C3\u30AF\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u9078\u629E\u53EF\uFF09",
|
|
40490
|
+
en: "Select the workbooks to analyze (multi-select allowed)"
|
|
40491
|
+
},
|
|
40492
|
+
async fetchOptions(state, rt) {
|
|
40493
|
+
if (!state.projects?.length) return [];
|
|
40494
|
+
const allProjects = await listAllProjects3(rt);
|
|
40495
|
+
const targetIds = await resolveSetupSelection({
|
|
40496
|
+
selected: state.projects,
|
|
40497
|
+
allSentinel: ALL_PROJECTS7,
|
|
40498
|
+
fetchAll: async () => allProjects.map((p) => p.id).filter((id) => id),
|
|
40499
|
+
limit: TABLEAU_SETUP_MAX_PROJECTS
|
|
40500
|
+
});
|
|
40501
|
+
const targetSet = new Set(targetIds);
|
|
40502
|
+
const workbooks = await listProjectResources(rt, "workbooks");
|
|
40503
|
+
const options = workbooks.filter((wb) => wb.id && wb.project?.id && targetSet.has(wb.project.id)).map((wb) => ({
|
|
40504
|
+
value: wb.id,
|
|
40505
|
+
label: wb.name ?? wb.id ?? "(unknown)"
|
|
40506
|
+
}));
|
|
40507
|
+
if (options.length === 0) return [];
|
|
40508
|
+
return [
|
|
40509
|
+
{
|
|
40510
|
+
value: ALL_WORKBOOKS,
|
|
40511
|
+
label: rt.language === "ja" ? "\u3059\u3079\u3066\u306E\u30EF\u30FC\u30AF\u30D6\u30C3\u30AF" : "All workbooks"
|
|
40512
|
+
},
|
|
40513
|
+
...options
|
|
40514
|
+
];
|
|
40515
|
+
},
|
|
40516
|
+
applyAnswer: (state, answer) => ({ ...state, workbooks: answer })
|
|
39315
40517
|
}
|
|
39316
40518
|
],
|
|
39317
40519
|
async finalize(state, rt) {
|
|
@@ -39320,25 +40522,33 @@ var tableauSetupFlow = {
|
|
|
39320
40522
|
}
|
|
39321
40523
|
const allProjects = await listAllProjects3(rt);
|
|
39322
40524
|
const projectById = new Map(allProjects.map((p) => [p.id, p]));
|
|
39323
|
-
const
|
|
40525
|
+
const targetProjectIds = await resolveSetupSelection({
|
|
39324
40526
|
selected: state.projects,
|
|
39325
40527
|
allSentinel: ALL_PROJECTS7,
|
|
39326
40528
|
fetchAll: async () => allProjects.map((p) => p.id).filter((id) => id),
|
|
39327
40529
|
limit: TABLEAU_SETUP_MAX_PROJECTS
|
|
39328
40530
|
});
|
|
39329
40531
|
const sections = ["## Tableau", ""];
|
|
39330
|
-
if (!
|
|
40532
|
+
if (!targetProjectIds.length) {
|
|
39331
40533
|
sections.push("_No projects selected._", "");
|
|
39332
40534
|
return sections.join("\n");
|
|
39333
40535
|
}
|
|
39334
|
-
const [
|
|
40536
|
+
const [allWorkbooks, datasources] = await Promise.all([
|
|
39335
40537
|
listProjectResources(rt, "workbooks"),
|
|
39336
40538
|
listProjectResources(rt, "datasources")
|
|
39337
40539
|
]);
|
|
40540
|
+
const projectIdSet = new Set(targetProjectIds);
|
|
40541
|
+
const targetWorkbooks = await resolveSetupSelection({
|
|
40542
|
+
selected: state.workbooks ?? [],
|
|
40543
|
+
allSentinel: ALL_WORKBOOKS,
|
|
40544
|
+
fetchAll: async () => allWorkbooks.filter((wb) => wb.id && wb.project?.id && projectIdSet.has(wb.project.id)).map((wb) => wb.id).filter(Boolean),
|
|
40545
|
+
limit: MAX_WORKBOOKS_DETAIL
|
|
40546
|
+
});
|
|
40547
|
+
const targetWorkbookSet = new Set(targetWorkbooks);
|
|
39338
40548
|
const workbooksByProject = /* @__PURE__ */ new Map();
|
|
39339
|
-
for (const wb of
|
|
40549
|
+
for (const wb of allWorkbooks) {
|
|
39340
40550
|
const pid = wb.project?.id;
|
|
39341
|
-
if (!pid) continue;
|
|
40551
|
+
if (!pid || !projectIdSet.has(pid)) continue;
|
|
39342
40552
|
const bucket = workbooksByProject.get(pid) ?? [];
|
|
39343
40553
|
bucket.push(wb);
|
|
39344
40554
|
workbooksByProject.set(pid, bucket);
|
|
@@ -39346,32 +40556,78 @@ var tableauSetupFlow = {
|
|
|
39346
40556
|
const datasourcesByProject = /* @__PURE__ */ new Map();
|
|
39347
40557
|
for (const ds of datasources) {
|
|
39348
40558
|
const pid = ds.project?.id;
|
|
39349
|
-
if (!pid) continue;
|
|
40559
|
+
if (!pid || !projectIdSet.has(pid)) continue;
|
|
39350
40560
|
const bucket = datasourcesByProject.get(pid) ?? [];
|
|
39351
40561
|
bucket.push(ds);
|
|
39352
40562
|
datasourcesByProject.set(pid, bucket);
|
|
39353
40563
|
}
|
|
39354
|
-
|
|
39355
|
-
|
|
39356
|
-
const
|
|
39357
|
-
sections.push(`### Project: ${name}`, ""
|
|
39358
|
-
const projectWorkbooks = workbooksByProject.get(
|
|
39359
|
-
|
|
39360
|
-
|
|
39361
|
-
|
|
39362
|
-
|
|
39363
|
-
|
|
39364
|
-
|
|
40564
|
+
const allDiscoveredColumns = [];
|
|
40565
|
+
for (const pid of targetProjectIds) {
|
|
40566
|
+
const project = projectById.get(pid);
|
|
40567
|
+
sections.push(`### Project: ${project?.name ?? pid}`, "");
|
|
40568
|
+
const projectWorkbooks = workbooksByProject.get(pid) ?? [];
|
|
40569
|
+
for (const wb of projectWorkbooks) {
|
|
40570
|
+
if (!wb.id) continue;
|
|
40571
|
+
const isDetailed = targetWorkbookSet.has(wb.id);
|
|
40572
|
+
sections.push(`#### Workbook: ${wb.name ?? wb.id}`, "");
|
|
40573
|
+
if (!isDetailed) continue;
|
|
40574
|
+
const views = await listViewsForWorkbook(rt, wb.id);
|
|
40575
|
+
if (views.length === 0) {
|
|
40576
|
+
sections.push("_No views found._", "");
|
|
40577
|
+
continue;
|
|
40578
|
+
}
|
|
40579
|
+
for (const view of views.slice(0, MAX_VIEWS_PER_WORKBOOK)) {
|
|
40580
|
+
if (!view.id) continue;
|
|
40581
|
+
sections.push(`##### View: ${view.name ?? view.id}`, "");
|
|
40582
|
+
const sample = await fetchViewDataSample(rt, view.id);
|
|
40583
|
+
if (!sample || sample.columns.length === 0) {
|
|
40584
|
+
sections.push("_Data not available._", "");
|
|
40585
|
+
continue;
|
|
40586
|
+
}
|
|
40587
|
+
allDiscoveredColumns.push(...sample.columns);
|
|
40588
|
+
sections.push(`| ${sample.columns.join(" | ")} |`);
|
|
40589
|
+
sections.push(`|${sample.columns.map(() => "---").join("|")}|`);
|
|
40590
|
+
for (const row of sample.rows) {
|
|
40591
|
+
const cells = row.map((c) => c.replace(/\|/g, "\\|"));
|
|
40592
|
+
sections.push(`| ${cells.join(" | ")} |`);
|
|
40593
|
+
}
|
|
40594
|
+
sections.push("");
|
|
40595
|
+
}
|
|
39365
40596
|
}
|
|
39366
|
-
const projectDatasources = datasourcesByProject.get(
|
|
39367
|
-
|
|
39368
|
-
|
|
39369
|
-
|
|
40597
|
+
const projectDatasources = datasourcesByProject.get(pid) ?? [];
|
|
40598
|
+
if (projectDatasources.length > 0) {
|
|
40599
|
+
sections.push(`#### Datasources (${projectDatasources.length})`, "");
|
|
40600
|
+
for (const ds of projectDatasources.slice(0, 25)) {
|
|
40601
|
+
sections.push(`- ${ds.name ?? ds.id ?? "(unknown)"}`);
|
|
40602
|
+
}
|
|
40603
|
+
sections.push("");
|
|
39370
40604
|
}
|
|
39371
|
-
|
|
39372
|
-
|
|
40605
|
+
}
|
|
40606
|
+
if (allDiscoveredColumns.length > 0) {
|
|
40607
|
+
const unique = [...new Set(allDiscoveredColumns.map((c) => c.toLowerCase()))];
|
|
40608
|
+
const themes = [];
|
|
40609
|
+
const hasPattern = (keywords) => unique.some((c) => keywords.some((k) => c.includes(k)));
|
|
40610
|
+
if (hasPattern(["revenue", "sales", "amount", "price", "cost", "profit", "\u58F2\u4E0A", "\u91D1\u984D", "\u5229\u76CA"]))
|
|
40611
|
+
themes.push("Revenue & profitability analysis (trends, breakdown by segment)");
|
|
40612
|
+
if (hasPattern(["date", "month", "year", "quarter", "day", "\u65E5\u4ED8", "\u6708", "\u5E74", "\u671F"]))
|
|
40613
|
+
themes.push("Time-series trend analysis (YoY, MoM comparisons)");
|
|
40614
|
+
if (hasPattern(["region", "country", "city", "state", "\u5730\u57DF", "\u56FD", "\u90FD\u5E02", "\u5E02"]))
|
|
40615
|
+
themes.push("Geographic/regional performance comparison");
|
|
40616
|
+
if (hasPattern(["product", "category", "item", "sku", "\u5546\u54C1", "\u30AB\u30C6\u30B4\u30EA"]))
|
|
40617
|
+
themes.push("Product/category mix analysis");
|
|
40618
|
+
if (hasPattern(["customer", "user", "account", "\u9867\u5BA2", "\u30E6\u30FC\u30B6\u30FC"]))
|
|
40619
|
+
themes.push("Customer segmentation and behavior analysis");
|
|
40620
|
+
if (hasPattern(["quantity", "count", "volume", "\u6570\u91CF", "\u4EF6\u6570"]))
|
|
40621
|
+
themes.push("Volume and demand pattern analysis");
|
|
40622
|
+
if (hasPattern(["rate", "ratio", "percentage", "%", "\u7387"]))
|
|
40623
|
+
themes.push("KPI ratio tracking and benchmarking");
|
|
40624
|
+
if (themes.length > 0) {
|
|
40625
|
+
sections.push("### Suggested Analysis Themes", "");
|
|
40626
|
+
for (const theme of themes) {
|
|
40627
|
+
sections.push(`- ${theme}`);
|
|
40628
|
+
}
|
|
40629
|
+
sections.push("");
|
|
39373
40630
|
}
|
|
39374
|
-
sections.push("");
|
|
39375
40631
|
}
|
|
39376
40632
|
return sections.join("\n");
|
|
39377
40633
|
}
|
|
@@ -39381,27 +40637,36 @@ var tableauSetupFlow = {
|
|
|
39381
40637
|
import { z as z98 } from "zod";
|
|
39382
40638
|
var DEFAULT_API_VERSION2 = "3.28";
|
|
39383
40639
|
var REQUEST_TIMEOUT_MS75 = 6e4;
|
|
39384
|
-
|
|
39385
|
-
|
|
39386
|
-
|
|
39387
|
-
|
|
39388
|
-
throw new Error(
|
|
39389
|
-
"Tableau session manager is not configured. Missing INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL or INTERNAL_SQUADBASE_SANDBOX_ID."
|
|
39390
|
-
);
|
|
40640
|
+
var cachedToken33 = null;
|
|
40641
|
+
async function getProxyToken33(config) {
|
|
40642
|
+
if (cachedToken33 && cachedToken33.expiresAt > Date.now() + 6e4) {
|
|
40643
|
+
return cachedToken33.token;
|
|
39391
40644
|
}
|
|
39392
|
-
const
|
|
39393
|
-
const url = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
40645
|
+
const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
|
|
39394
40646
|
const res = await fetch(url, {
|
|
39395
40647
|
method: "POST",
|
|
39396
|
-
headers: {
|
|
40648
|
+
headers: {
|
|
40649
|
+
"Content-Type": "application/json",
|
|
40650
|
+
"x-api-key": config.appApiKey,
|
|
40651
|
+
"project-id": config.projectId
|
|
40652
|
+
},
|
|
40653
|
+
body: JSON.stringify({
|
|
40654
|
+
sandboxId: config.sandboxId,
|
|
40655
|
+
issuedBy: "coding-agent"
|
|
40656
|
+
})
|
|
39397
40657
|
});
|
|
39398
40658
|
if (!res.ok) {
|
|
39399
|
-
const
|
|
40659
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
39400
40660
|
throw new Error(
|
|
39401
|
-
`Failed to
|
|
40661
|
+
`Failed to get proxy token: HTTP ${res.status} ${errorText}`
|
|
39402
40662
|
);
|
|
39403
40663
|
}
|
|
39404
|
-
|
|
40664
|
+
const data = await res.json();
|
|
40665
|
+
cachedToken33 = {
|
|
40666
|
+
token: data.token,
|
|
40667
|
+
expiresAt: new Date(data.expiresAt).getTime()
|
|
40668
|
+
};
|
|
40669
|
+
return data.token;
|
|
39405
40670
|
}
|
|
39406
40671
|
function buildBaseUrl7(serverUrl, apiVersion) {
|
|
39407
40672
|
return `${serverUrl.replace(/\/$/, "")}/api/${apiVersion}`;
|
|
@@ -39443,7 +40708,7 @@ All paths are relative to {serverUrl}/api/{apiVersion}. Use the literal placehol
|
|
|
39443
40708
|
Accept and Content-Type headers default to application/json so list responses come back as JSON instead of Tableau's default XML.`,
|
|
39444
40709
|
inputSchema: inputSchema98,
|
|
39445
40710
|
outputSchema: outputSchema98,
|
|
39446
|
-
async execute({ connectionId, method, path: path5, queryParams, body }, connections) {
|
|
40711
|
+
async execute({ connectionId, method, path: path5, queryParams, body }, connections, config) {
|
|
39447
40712
|
const connection2 = connections.find((c) => c.id === connectionId);
|
|
39448
40713
|
if (!connection2) {
|
|
39449
40714
|
return {
|
|
@@ -39458,50 +40723,42 @@ Accept and Content-Type headers default to application/json so list responses co
|
|
|
39458
40723
|
const serverUrl = parameters81.serverUrl.getValue(connection2);
|
|
39459
40724
|
const apiVersion = parameters81.apiVersion.tryGetValue(connection2) || DEFAULT_API_VERSION2;
|
|
39460
40725
|
const trimmedPath = path5.trim().replace(/^([^/])/, "/$1");
|
|
39461
|
-
const queryString = queryParams ? `?${new URLSearchParams(queryParams).toString()}` : "";
|
|
39462
40726
|
const baseUrl = buildBaseUrl7(serverUrl, apiVersion);
|
|
40727
|
+
let url = `${baseUrl}${trimmedPath}`;
|
|
40728
|
+
if (queryParams) {
|
|
40729
|
+
url += `?${new URLSearchParams(queryParams).toString()}`;
|
|
40730
|
+
}
|
|
40731
|
+
const token = await getProxyToken33(config.oauthProxy);
|
|
40732
|
+
const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
39463
40733
|
const controller = new AbortController();
|
|
39464
40734
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS75);
|
|
39465
40735
|
try {
|
|
39466
|
-
|
|
39467
|
-
|
|
39468
|
-
|
|
39469
|
-
|
|
39470
|
-
|
|
39471
|
-
|
|
39472
|
-
|
|
39473
|
-
|
|
39474
|
-
const init = {
|
|
40736
|
+
const response = await fetch(proxyUrl, {
|
|
40737
|
+
method: "POST",
|
|
40738
|
+
headers: {
|
|
40739
|
+
"Content-Type": "application/json",
|
|
40740
|
+
Authorization: `Bearer ${token}`
|
|
40741
|
+
},
|
|
40742
|
+
body: JSON.stringify({
|
|
40743
|
+
url,
|
|
39475
40744
|
method,
|
|
39476
|
-
|
|
39477
|
-
|
|
39478
|
-
|
|
39479
|
-
|
|
39480
|
-
|
|
39481
|
-
|
|
39482
|
-
|
|
39483
|
-
|
|
39484
|
-
|
|
39485
|
-
|
|
39486
|
-
const response = await fetch(url, init);
|
|
39487
|
-
const text = await response.text();
|
|
39488
|
-
const data = text ? (() => {
|
|
39489
|
-
try {
|
|
39490
|
-
return JSON.parse(text);
|
|
39491
|
-
} catch {
|
|
39492
|
-
return text;
|
|
39493
|
-
}
|
|
39494
|
-
})() : null;
|
|
39495
|
-
if (response.status === 401 && attempt === 0) {
|
|
39496
|
-
attempt++;
|
|
39497
|
-
continue;
|
|
39498
|
-
}
|
|
39499
|
-
if (!response.ok) {
|
|
39500
|
-
const errorMessage = data && typeof data === "object" && "error" in data ? JSON.stringify(data.error) : typeof data === "string" && data ? data : `HTTP ${response.status} ${response.statusText}`;
|
|
39501
|
-
return { success: false, error: errorMessage };
|
|
40745
|
+
...body !== void 0 ? { body } : {}
|
|
40746
|
+
}),
|
|
40747
|
+
signal: controller.signal
|
|
40748
|
+
});
|
|
40749
|
+
const text = await response.text();
|
|
40750
|
+
const data = text ? (() => {
|
|
40751
|
+
try {
|
|
40752
|
+
return JSON.parse(text);
|
|
40753
|
+
} catch {
|
|
40754
|
+
return text;
|
|
39502
40755
|
}
|
|
39503
|
-
|
|
40756
|
+
})() : null;
|
|
40757
|
+
if (!response.ok) {
|
|
40758
|
+
const errorMessage = data && typeof data === "object" && "error" in data ? JSON.stringify(data.error) : typeof data === "string" && data ? data : `HTTP ${response.status} ${response.statusText}`;
|
|
40759
|
+
return { success: false, error: errorMessage };
|
|
39504
40760
|
}
|
|
40761
|
+
return { success: true, status: response.status, data };
|
|
39505
40762
|
} finally {
|
|
39506
40763
|
clearTimeout(timeout);
|
|
39507
40764
|
}
|
|
@@ -39693,12 +40950,12 @@ export default async function handler(c: Context) {
|
|
|
39693
40950
|
import { z as z99 } from "zod";
|
|
39694
40951
|
var BASE_HOST13 = "https://graph.microsoft.com";
|
|
39695
40952
|
var BASE_PATH_SEGMENT19 = "/v1.0";
|
|
39696
|
-
var
|
|
40953
|
+
var BASE_URL66 = `${BASE_HOST13}${BASE_PATH_SEGMENT19}`;
|
|
39697
40954
|
var REQUEST_TIMEOUT_MS76 = 6e4;
|
|
39698
|
-
var
|
|
39699
|
-
async function
|
|
39700
|
-
if (
|
|
39701
|
-
return
|
|
40955
|
+
var cachedToken34 = null;
|
|
40956
|
+
async function getProxyToken34(config) {
|
|
40957
|
+
if (cachedToken34 && cachedToken34.expiresAt > Date.now() + 6e4) {
|
|
40958
|
+
return cachedToken34.token;
|
|
39702
40959
|
}
|
|
39703
40960
|
const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
|
|
39704
40961
|
const res = await fetch(url, {
|
|
@@ -39720,7 +40977,7 @@ async function getProxyToken33(config) {
|
|
|
39720
40977
|
);
|
|
39721
40978
|
}
|
|
39722
40979
|
const data = await res.json();
|
|
39723
|
-
|
|
40980
|
+
cachedToken34 = {
|
|
39724
40981
|
token: data.token,
|
|
39725
40982
|
expiresAt: new Date(data.expiresAt).getTime()
|
|
39726
40983
|
};
|
|
@@ -39772,12 +41029,12 @@ For full-text search use the \`$search\` query parameter (must be wrapped in dou
|
|
|
39772
41029
|
);
|
|
39773
41030
|
try {
|
|
39774
41031
|
const normalizedPath = normalizeRequestPath(path5, BASE_PATH_SEGMENT19);
|
|
39775
|
-
let url = `${
|
|
41032
|
+
let url = `${BASE_URL66}${normalizedPath}`;
|
|
39776
41033
|
if (queryParams) {
|
|
39777
41034
|
const searchParams = new URLSearchParams(queryParams);
|
|
39778
41035
|
url += `?${searchParams.toString()}`;
|
|
39779
41036
|
}
|
|
39780
|
-
const token = await
|
|
41037
|
+
const token = await getProxyToken34(config.oauthProxy);
|
|
39781
41038
|
const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
39782
41039
|
const controller = new AbortController();
|
|
39783
41040
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS76);
|