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