@pipedream/google_slides 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/actions/create-image/create-image.mjs +1 -1
- package/actions/create-page-element/create-page-element.mjs +1 -1
- package/actions/create-presentation/create-presentation.mjs +1 -1
- package/actions/create-slide/create-slide.mjs +1 -1
- package/actions/create-table/create-table.mjs +1 -1
- package/actions/delete-page-element/delete-page-element.mjs +1 -1
- package/actions/delete-slide/delete-slide.mjs +1 -1
- package/actions/delete-table-column/delete-table-column.mjs +1 -1
- package/actions/delete-table-row/delete-table-row.mjs +1 -1
- package/actions/find-presentation/find-presentation.mjs +1 -1
- package/actions/format-paragraph/format-paragraph.mjs +236 -0
- package/actions/format-shape/format-shape.mjs +193 -0
- package/actions/format-slide-background/format-slide-background.mjs +74 -0
- package/actions/format-table-cell/format-table-cell.mjs +162 -0
- package/actions/format-text/format-text.mjs +248 -0
- package/actions/get-presentation/get-presentation.mjs +2 -1
- package/actions/insert-table-columns/insert-table-columns.mjs +1 -1
- package/actions/insert-table-rows/insert-table-rows.mjs +1 -1
- package/actions/insert-text/insert-text.mjs +1 -1
- package/actions/insert-text-into-table/insert-text-into-table.mjs +1 -1
- package/actions/merge-data/merge-data.mjs +1 -1
- package/actions/position-element/position-element.mjs +219 -0
- package/actions/refresh-chart/refresh-chart.mjs +1 -1
- package/actions/replace-all-text/replace-all-text.mjs +1 -1
- package/common/constants.mjs +110 -0
- package/common/utils.mjs +115 -0
- package/google_slides.app.mjs +101 -0
- package/package.json +1 -1
- package/sources/new-presentation/new-presentation.mjs +1 -1
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "google_slides-refresh-chart",
|
|
5
5
|
name: "Refresh a chart",
|
|
6
6
|
description: "Refresh a chart from Sheets. [See the docs here](https://developers.google.com/slides/api/samples/elements#refresh_a_chart_from_sheets)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.9",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: false,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "google_slides-replace-all-text",
|
|
5
5
|
name: "Replace All Text",
|
|
6
6
|
description: "Replace all text in a presentation. [See the documentation](https://developers.google.com/workspace/slides/api/reference/rest/v1/presentations/request#ReplaceAllTextRequest)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.5",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: true,
|
|
10
10
|
openWorldHint: true,
|
package/common/constants.mjs
CHANGED
|
@@ -141,3 +141,113 @@ export const SHAPE_TYPES = [
|
|
|
141
141
|
"ELLIPSE_RIBBON_2",
|
|
142
142
|
"CLOUD_CALLOUT",
|
|
143
143
|
];
|
|
144
|
+
|
|
145
|
+
// Enum values used by the styling requests, checked against the current API
|
|
146
|
+
// reference. https://developers.google.com/workspace/slides/api/reference/rest/v1/presentations/request
|
|
147
|
+
|
|
148
|
+
export const ALIGNMENTS = [
|
|
149
|
+
"START",
|
|
150
|
+
"CENTER",
|
|
151
|
+
"END",
|
|
152
|
+
"JUSTIFIED",
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
export const CONTENT_ALIGNMENTS = [
|
|
156
|
+
"TOP",
|
|
157
|
+
"MIDDLE",
|
|
158
|
+
"BOTTOM",
|
|
159
|
+
];
|
|
160
|
+
|
|
161
|
+
export const DASH_STYLES = [
|
|
162
|
+
"SOLID",
|
|
163
|
+
"DOT",
|
|
164
|
+
"DASH",
|
|
165
|
+
"DASH_DOT",
|
|
166
|
+
"LONG_DASH",
|
|
167
|
+
"LONG_DASH_DOT",
|
|
168
|
+
];
|
|
169
|
+
|
|
170
|
+
export const Z_ORDER_OPERATIONS = [
|
|
171
|
+
"BRING_TO_FRONT",
|
|
172
|
+
"BRING_FORWARD",
|
|
173
|
+
"SEND_BACKWARD",
|
|
174
|
+
"SEND_TO_BACK",
|
|
175
|
+
];
|
|
176
|
+
|
|
177
|
+
// Theme colors resolve against the deck's own ColorScheme, so a caller can style
|
|
178
|
+
// with the presentation's palette instead of hardcoding hex values.
|
|
179
|
+
export const THEME_COLORS = [
|
|
180
|
+
"DARK1",
|
|
181
|
+
"LIGHT1",
|
|
182
|
+
"DARK2",
|
|
183
|
+
"LIGHT2",
|
|
184
|
+
"ACCENT1",
|
|
185
|
+
"ACCENT2",
|
|
186
|
+
"ACCENT3",
|
|
187
|
+
"ACCENT4",
|
|
188
|
+
"ACCENT5",
|
|
189
|
+
"ACCENT6",
|
|
190
|
+
"HYPERLINK",
|
|
191
|
+
"FOLLOWED_HYPERLINK",
|
|
192
|
+
"TEXT1",
|
|
193
|
+
"BACKGROUND1",
|
|
194
|
+
"TEXT2",
|
|
195
|
+
"BACKGROUND2",
|
|
196
|
+
];
|
|
197
|
+
|
|
198
|
+
// Dimension.unit - points, rather than the API's other unit (EMU).
|
|
199
|
+
export const POINTS = "PT";
|
|
200
|
+
export const EMU = "EMU";
|
|
201
|
+
|
|
202
|
+
// 1 inch = 72 pt = 914400 EMU. A transform carries a single unit for all six
|
|
203
|
+
// matrix elements, so caller-supplied points must be converted into whatever
|
|
204
|
+
// unit the element already uses rather than mixed in.
|
|
205
|
+
export const EMU_PER_POINT = 12700;
|
|
206
|
+
|
|
207
|
+
// Range.type. The API expresses the three range shapes as distinct types rather
|
|
208
|
+
// than as optional bounds, and rejects FIXED_RANGE that carries no end index.
|
|
209
|
+
export const TEXT_RANGE_ALL = "ALL";
|
|
210
|
+
export const TEXT_RANGE_FROM_START_INDEX = "FROM_START_INDEX";
|
|
211
|
+
export const TEXT_RANGE_FIXED_RANGE = "FIXED_RANGE";
|
|
212
|
+
|
|
213
|
+
// BulletGlyphPreset. NOTE: these are NOT the same spellings the Google Docs API
|
|
214
|
+
// uses - Slides says DIGIT where Docs says DECIMAL - so they cannot be shared
|
|
215
|
+
// with the google_docs connector.
|
|
216
|
+
export const BULLET_PRESETS = [
|
|
217
|
+
"BULLET_DISC_CIRCLE_SQUARE",
|
|
218
|
+
"BULLET_DIAMONDX_ARROW3D_SQUARE",
|
|
219
|
+
"BULLET_CHECKBOX",
|
|
220
|
+
"BULLET_ARROW_DIAMOND_DISC",
|
|
221
|
+
"BULLET_STAR_CIRCLE_SQUARE",
|
|
222
|
+
"BULLET_ARROW3D_CIRCLE_SQUARE",
|
|
223
|
+
"BULLET_LEFTTRIANGLE_DIAMOND_DISC",
|
|
224
|
+
"BULLET_DIAMONDX_HOLLOWDIAMOND_SQUARE",
|
|
225
|
+
"BULLET_DIAMOND_CIRCLE_SQUARE",
|
|
226
|
+
"NUMBERED_DIGIT_ALPHA_ROMAN",
|
|
227
|
+
"NUMBERED_DIGIT_ALPHA_ROMAN_PARENS",
|
|
228
|
+
"NUMBERED_DIGIT_NESTED",
|
|
229
|
+
"NUMBERED_UPPERALPHA_ALPHA_ROMAN",
|
|
230
|
+
"NUMBERED_UPPERROMAN_UPPERALPHA_DIGIT",
|
|
231
|
+
"NUMBERED_ZERODIGIT_ALPHA_ROMAN",
|
|
232
|
+
];
|
|
233
|
+
|
|
234
|
+
// Sentinel for the Bullets prop meaning "strip existing bullets".
|
|
235
|
+
export const BULLETS_NONE = "NONE";
|
|
236
|
+
|
|
237
|
+
export const BASELINE_OFFSETS = [
|
|
238
|
+
"NONE",
|
|
239
|
+
"SUPERSCRIPT",
|
|
240
|
+
"SUBSCRIPT",
|
|
241
|
+
];
|
|
242
|
+
|
|
243
|
+
export const TEXT_DIRECTIONS = [
|
|
244
|
+
"LEFT_TO_RIGHT",
|
|
245
|
+
"RIGHT_TO_LEFT",
|
|
246
|
+
];
|
|
247
|
+
|
|
248
|
+
export const SPACING_MODES = [
|
|
249
|
+
"NEVER_COLLAPSE",
|
|
250
|
+
"COLLAPSE_LISTS",
|
|
251
|
+
];
|
|
252
|
+
|
|
253
|
+
export const OPACITY_SCALE = 100;
|
package/common/utils.mjs
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { ConfigurationError } from "@pipedream/platform";
|
|
2
|
+
import {
|
|
3
|
+
TEXT_RANGE_ALL,
|
|
4
|
+
TEXT_RANGE_FIXED_RANGE,
|
|
5
|
+
OPACITY_SCALE,
|
|
6
|
+
POINTS,
|
|
7
|
+
TEXT_RANGE_FROM_START_INDEX,
|
|
8
|
+
THEME_COLORS,
|
|
9
|
+
} from "./constants.mjs";
|
|
10
|
+
|
|
11
|
+
function toOpaqueColor(value) {
|
|
12
|
+
const trimmed = String(value).trim();
|
|
13
|
+
const themeColor = trimmed.toUpperCase();
|
|
14
|
+
if (THEME_COLORS.includes(themeColor)) {
|
|
15
|
+
return {
|
|
16
|
+
themeColor,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const hex = trimmed.replace(/^#/, "");
|
|
21
|
+
if (!/^[0-9a-fA-F]{6}$/.test(hex)) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const channel = (start) => parseInt(hex.slice(start, start + 2), 16) / 255;
|
|
25
|
+
return {
|
|
26
|
+
rgbColor: {
|
|
27
|
+
red: channel(0),
|
|
28
|
+
green: channel(2),
|
|
29
|
+
blue: channel(4),
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function toSolidFill(value, opacityPercent) {
|
|
35
|
+
const color = value == null || value === ""
|
|
36
|
+
? null
|
|
37
|
+
: toOpaqueColor(value);
|
|
38
|
+
if (value && !color) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const fill = {};
|
|
42
|
+
if (color) {
|
|
43
|
+
fill.color = color;
|
|
44
|
+
}
|
|
45
|
+
if (opacityPercent != null) {
|
|
46
|
+
fill.alpha = opacityPercent / OPACITY_SCALE;
|
|
47
|
+
}
|
|
48
|
+
return Object.keys(fill).length
|
|
49
|
+
? fill
|
|
50
|
+
: null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function buildTextRange(startIndex, endIndex) {
|
|
54
|
+
if (startIndex == null && endIndex == null) {
|
|
55
|
+
return {
|
|
56
|
+
type: TEXT_RANGE_ALL,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (startIndex == null) {
|
|
60
|
+
throw new ConfigurationError("End Index needs a Start Index. Provide both to style a fixed span, Start Index on its own to style from there to the end, or neither to style all of the text.");
|
|
61
|
+
}
|
|
62
|
+
if (endIndex == null) {
|
|
63
|
+
return {
|
|
64
|
+
type: TEXT_RANGE_FROM_START_INDEX,
|
|
65
|
+
startIndex,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (endIndex <= startIndex) {
|
|
69
|
+
throw new ConfigurationError(`End Index (${endIndex}) must be greater than Start Index (${startIndex}).`);
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
type: TEXT_RANGE_FIXED_RANGE,
|
|
73
|
+
startIndex,
|
|
74
|
+
endIndex,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function styleBuilder() {
|
|
79
|
+
const style = {};
|
|
80
|
+
const fields = [];
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
style,
|
|
84
|
+
fields,
|
|
85
|
+
set(name, value) {
|
|
86
|
+
if (value == null) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
style[name] = value;
|
|
90
|
+
fields.push(name);
|
|
91
|
+
},
|
|
92
|
+
setDimension(name, magnitude, unit = POINTS) {
|
|
93
|
+
if (magnitude == null) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
this.set(name, {
|
|
97
|
+
magnitude,
|
|
98
|
+
unit,
|
|
99
|
+
});
|
|
100
|
+
},
|
|
101
|
+
get isEmpty() {
|
|
102
|
+
return !fields.length;
|
|
103
|
+
},
|
|
104
|
+
get mask() {
|
|
105
|
+
return fields.join(",");
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export default {
|
|
111
|
+
styleBuilder,
|
|
112
|
+
toOpaqueColor,
|
|
113
|
+
toSolidFill,
|
|
114
|
+
buildTextRange,
|
|
115
|
+
};
|
package/google_slides.app.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ConfigurationError } from "@pipedream/platform";
|
|
2
2
|
import slides from "@googleapis/slides";
|
|
3
3
|
import googleDrive from "@pipedream/google_drive";
|
|
4
|
+
import { CONTENT_ALIGNMENTS } from "./common/constants.mjs";
|
|
4
5
|
|
|
5
6
|
export default {
|
|
6
7
|
...googleDrive,
|
|
@@ -20,6 +21,72 @@ export default {
|
|
|
20
21
|
return this.listPresentationsOptions(driveId, nextPageToken);
|
|
21
22
|
},
|
|
22
23
|
},
|
|
24
|
+
staticPresentationId: {
|
|
25
|
+
type: "string",
|
|
26
|
+
label: "Presentation ID",
|
|
27
|
+
description: "The ID of the presentation. This is the long string in the URL: `https://docs.google.com/presentation/d/{PRESENTATION_ID}/edit`. A full presentation URL is also accepted. Use **Find Presentation** to resolve a name to its ID.",
|
|
28
|
+
},
|
|
29
|
+
staticSlideId: {
|
|
30
|
+
type: "string",
|
|
31
|
+
label: "Slide ID",
|
|
32
|
+
description: "The object ID of the slide (e.g. `p1` or `g1a2b3c4d5`). Use **Get Presentation** and read `slides[].objectId`.",
|
|
33
|
+
},
|
|
34
|
+
pageElementId: {
|
|
35
|
+
type: "string",
|
|
36
|
+
label: "Page Element ID",
|
|
37
|
+
description: "The object ID of the shape, image, table, or other page element to act on. Use **Get Presentation** and read `slides[].pageElements[].objectId`.",
|
|
38
|
+
},
|
|
39
|
+
// Shared by the styling actions; individual actions override the label or
|
|
40
|
+
// description where their wording differs.
|
|
41
|
+
rowIndex: {
|
|
42
|
+
type: "integer",
|
|
43
|
+
label: "Row Index",
|
|
44
|
+
description: "The 0-based row of the target table cell.",
|
|
45
|
+
min: 0,
|
|
46
|
+
optional: true,
|
|
47
|
+
},
|
|
48
|
+
columnIndex: {
|
|
49
|
+
type: "integer",
|
|
50
|
+
label: "Column Index",
|
|
51
|
+
description: "The 0-based column of the target table cell.",
|
|
52
|
+
min: 0,
|
|
53
|
+
optional: true,
|
|
54
|
+
},
|
|
55
|
+
startIndex: {
|
|
56
|
+
type: "integer",
|
|
57
|
+
label: "Start Index",
|
|
58
|
+
description: "Character index to style from, inclusive. On its own, styles from here to the end of the text. Omit both indices to style all of it.",
|
|
59
|
+
min: 0,
|
|
60
|
+
optional: true,
|
|
61
|
+
},
|
|
62
|
+
endIndex: {
|
|
63
|
+
type: "integer",
|
|
64
|
+
label: "End Index",
|
|
65
|
+
description: "Character index to style up to, exclusive. Requires **Start Index**, and must be greater than it.",
|
|
66
|
+
min: 0,
|
|
67
|
+
optional: true,
|
|
68
|
+
},
|
|
69
|
+
backgroundColor: {
|
|
70
|
+
type: "string",
|
|
71
|
+
label: "Background Color",
|
|
72
|
+
description: "A hex code (e.g. `#EEEEEE`) or one of the deck's theme colors (e.g. `ACCENT1`).",
|
|
73
|
+
optional: true,
|
|
74
|
+
},
|
|
75
|
+
backgroundOpacity: {
|
|
76
|
+
type: "integer",
|
|
77
|
+
label: "Background Opacity",
|
|
78
|
+
description: "Opacity as a whole percentage, from `0` (fully transparent) to `100` (fully opaque). Can be set on its own to change an existing fill's opacity without restating its color.",
|
|
79
|
+
min: 0,
|
|
80
|
+
max: 100,
|
|
81
|
+
optional: true,
|
|
82
|
+
},
|
|
83
|
+
contentAlignment: {
|
|
84
|
+
type: "string",
|
|
85
|
+
label: "Content Alignment",
|
|
86
|
+
description: "Vertical alignment of the text within the element. One of `TOP`, `MIDDLE` or `BOTTOM` - e.g. `MIDDLE` to centre the text vertically.",
|
|
87
|
+
options: CONTENT_ALIGNMENTS,
|
|
88
|
+
optional: true,
|
|
89
|
+
},
|
|
23
90
|
layoutId: {
|
|
24
91
|
type: "string",
|
|
25
92
|
label: "Layout ID",
|
|
@@ -280,6 +347,40 @@ export default {
|
|
|
280
347
|
};
|
|
281
348
|
return (await slides.presentations.get(request)).data;
|
|
282
349
|
},
|
|
350
|
+
_findPageElement(presentation, objectId) {
|
|
351
|
+
const walk = (elements, slideId, groupId) => {
|
|
352
|
+
for (const element of elements || []) {
|
|
353
|
+
if (element.objectId === objectId) {
|
|
354
|
+
return {
|
|
355
|
+
element,
|
|
356
|
+
slideId,
|
|
357
|
+
groupId,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
const found = walk(element.elementGroup?.children, slideId, element.objectId);
|
|
361
|
+
if (found) {
|
|
362
|
+
return found;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return null;
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
for (const slide of presentation.slides || []) {
|
|
369
|
+
const found = walk(slide.pageElements, slide.objectId);
|
|
370
|
+
if (found) {
|
|
371
|
+
return found;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return null;
|
|
375
|
+
},
|
|
376
|
+
async getPageElement(presentationId, objectId) {
|
|
377
|
+
const presentation = await this.getPresentation(presentationId);
|
|
378
|
+
const found = this._findPageElement(presentation, objectId);
|
|
379
|
+
if (!found) {
|
|
380
|
+
throw new ConfigurationError(`No page element with ID "${objectId}" was found in presentation ${presentationId}. Use Get Presentation to list slides[].pageElements[].objectId.`);
|
|
381
|
+
}
|
|
382
|
+
return found;
|
|
383
|
+
},
|
|
283
384
|
async getSlide(presentationId, slideId) {
|
|
284
385
|
const slides = this.slides();
|
|
285
386
|
const request = {
|
package/package.json
CHANGED