@memberjunction/excel-addin-server 0.0.0 → 6.2.0-edge.7
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/LICENSE +183 -0
- package/README.md +88 -28
- package/dist/catalog.d.ts +29 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +242 -0
- package/dist/catalog.js.map +1 -0
- package/dist/connection.d.ts +31 -0
- package/dist/connection.d.ts.map +1 -0
- package/dist/connection.js +111 -0
- package/dist/connection.js.map +1 -0
- package/dist/extension.d.ts +46 -0
- package/dist/extension.d.ts.map +1 -0
- package/dist/extension.js +177 -0
- package/dist/extension.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest-builder.d.ts +18 -0
- package/dist/manifest-builder.d.ts.map +1 -0
- package/dist/manifest-builder.js +126 -0
- package/dist/manifest-builder.js.map +1 -0
- package/dist/operations.d.ts +45 -0
- package/dist/operations.d.ts.map +1 -0
- package/dist/operations.js +160 -0
- package/dist/operations.js.map +1 -0
- package/dist/runtime.d.ts +53 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +88 -0
- package/dist/runtime.js.map +1 -0
- package/dist/settings.d.ts +48 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +115 -0
- package/dist/settings.js.map +1 -0
- package/dist/sources.d.ts +31 -0
- package/dist/sources.d.ts.map +1 -0
- package/dist/sources.js +230 -0
- package/dist/sources.js.map +1 -0
- package/dist/workbook-builder.d.ts +21 -0
- package/dist/workbook-builder.d.ts.map +1 -0
- package/dist/workbook-builder.js +122 -0
- package/dist/workbook-builder.js.map +1 -0
- package/package.json +39 -8
package/dist/sources.js
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Resolves the saved views, entities, and saved queries an Open in Excel or in-pane
|
|
3
|
+
* picker request names into workbook sources: their names, columns and data types, and a query's
|
|
4
|
+
* checked parameter values.
|
|
5
|
+
*
|
|
6
|
+
* Everything is read AS the caller, so a view, entity, or query they can't see is refused here,
|
|
7
|
+
* before a workbook or sheet exists. This reads metadata only (no rows); the add-in pane fetches
|
|
8
|
+
* rows later, as whoever opens the file, through GraphQL operations that check permissions again.
|
|
9
|
+
*
|
|
10
|
+
* @module @memberjunction/excel-addin-server
|
|
11
|
+
*/
|
|
12
|
+
import { EntityFieldTSType, TypeScriptTypeFromSQLType, } from '@memberjunction/core';
|
|
13
|
+
import { IsValidUUID, UUIDsEqual } from '@memberjunction/global';
|
|
14
|
+
import { EXCEL_MAX_SOURCES_PER_WORKBOOK, MakeUniqueSheetName, } from '@memberjunction/excel-addin';
|
|
15
|
+
/** A refusal whose message is safe to show the person who asked. */
|
|
16
|
+
export class ExcelSourceError extends Error {
|
|
17
|
+
constructor(message) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = 'ExcelSourceError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const MAX_PARAMETER_TEXT = 32767;
|
|
23
|
+
/**
|
|
24
|
+
* Resolves and checks every requested source, in order. Throws {@link ExcelSourceError} for the
|
|
25
|
+
* first one the caller can't use.
|
|
26
|
+
*/
|
|
27
|
+
export async function ResolveWorkbookSources(requests, provider, user) {
|
|
28
|
+
validateRequests(requests);
|
|
29
|
+
const usedSheetNames = new Set();
|
|
30
|
+
const sources = [];
|
|
31
|
+
// At most EXCEL_MAX_SOURCES_PER_WORKBOOK iterations; each view is loaded AS the user because that
|
|
32
|
+
// load is what sets the permission context UserCanView reads.
|
|
33
|
+
for (const [index, request] of requests.entries()) {
|
|
34
|
+
const resolved = await ResolveSingleWorkbookSource(request, provider, user);
|
|
35
|
+
sources.push({ ...resolved, Key: `s${index + 1}`, SheetName: MakeUniqueSheetName(resolved.Name, usedSheetNames) });
|
|
36
|
+
}
|
|
37
|
+
return sources;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Resolves and authorizes a single view, entity, or saved query request for `user`.
|
|
41
|
+
*/
|
|
42
|
+
export async function ResolveSingleWorkbookSource(request, provider, user) {
|
|
43
|
+
validateSingleRequest(request);
|
|
44
|
+
switch (request.Kind) {
|
|
45
|
+
case 'View':
|
|
46
|
+
return resolveView(request.ID, provider, user);
|
|
47
|
+
case 'Entity':
|
|
48
|
+
return resolveEntity(request.ID, provider, user);
|
|
49
|
+
case 'Query':
|
|
50
|
+
return resolveQuery(request, provider, user);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** The data type the pane uses for an entity field's values. */
|
|
54
|
+
export function DataTypeForEntityField(field) {
|
|
55
|
+
switch (field.TSType) {
|
|
56
|
+
case EntityFieldTSType.Number:
|
|
57
|
+
return 'Number';
|
|
58
|
+
case EntityFieldTSType.Boolean:
|
|
59
|
+
return 'Boolean';
|
|
60
|
+
case EntityFieldTSType.Date:
|
|
61
|
+
return isDateOnlySQLType(field.Type) ? 'Date' : 'DateTime';
|
|
62
|
+
default:
|
|
63
|
+
return 'Text';
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** The data type the pane uses for a query field, from its SQL base type; `Text` when unknown. */
|
|
67
|
+
export function DataTypeForSQLType(sqlType) {
|
|
68
|
+
const trimmed = (sqlType ?? '').trim();
|
|
69
|
+
if (!trimmed) {
|
|
70
|
+
return 'Text';
|
|
71
|
+
}
|
|
72
|
+
switch (TypeScriptTypeFromSQLType(trimmed)) {
|
|
73
|
+
case 'number':
|
|
74
|
+
return 'Number';
|
|
75
|
+
case 'boolean':
|
|
76
|
+
return 'Boolean';
|
|
77
|
+
case 'Date':
|
|
78
|
+
return isDateOnlySQLType(trimmed) ? 'Date' : 'DateTime';
|
|
79
|
+
default:
|
|
80
|
+
return 'Text';
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function validateRequests(requests) {
|
|
84
|
+
if (!Array.isArray(requests) || requests.length === 0) {
|
|
85
|
+
throw new ExcelSourceError('Choose at least one view, entity, or query to open in Excel.');
|
|
86
|
+
}
|
|
87
|
+
if (requests.length > EXCEL_MAX_SOURCES_PER_WORKBOOK) {
|
|
88
|
+
throw new ExcelSourceError(`A workbook can hold at most ${EXCEL_MAX_SOURCES_PER_WORKBOOK} views and queries.`);
|
|
89
|
+
}
|
|
90
|
+
for (const request of requests) {
|
|
91
|
+
validateSingleRequest(request);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function validateSingleRequest(request) {
|
|
95
|
+
if (request?.Kind !== 'View' && request?.Kind !== 'Entity' && request?.Kind !== 'Query') {
|
|
96
|
+
throw new ExcelSourceError('Only saved views, entities, and saved queries can be opened in Excel.');
|
|
97
|
+
}
|
|
98
|
+
if (!IsValidUUID(request.ID)) {
|
|
99
|
+
throw new ExcelSourceError('That view, entity, or query ID is not valid.');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async function resolveView(viewID, provider, user) {
|
|
103
|
+
const view = await provider.GetEntityObject('MJ: User Views', user);
|
|
104
|
+
const loaded = await view.Load(viewID);
|
|
105
|
+
if (!loaded || !view.UserCanView) {
|
|
106
|
+
throw new ExcelSourceError('That saved view doesn\'t exist, or you don\'t have access to it.');
|
|
107
|
+
}
|
|
108
|
+
const entity = view.ViewEntityInfo;
|
|
109
|
+
if (!entity || !entity.GetUserPermisions(user).CanRead) {
|
|
110
|
+
throw new ExcelSourceError(`You don't have access to the data in the view "${view.Name}".`);
|
|
111
|
+
}
|
|
112
|
+
const columns = viewColumns(view.Columns, entity.Fields);
|
|
113
|
+
if (columns.length === 0) {
|
|
114
|
+
throw new ExcelSourceError(`The view "${view.Name}" has no columns to show.`);
|
|
115
|
+
}
|
|
116
|
+
const resolved = {
|
|
117
|
+
Kind: 'View',
|
|
118
|
+
ID: view.ID,
|
|
119
|
+
Name: view.Name,
|
|
120
|
+
Columns: columns,
|
|
121
|
+
};
|
|
122
|
+
if (typeof entity.Name === 'string' && entity.Name.trim().length > 0) {
|
|
123
|
+
resolved.EntityName = entity.Name;
|
|
124
|
+
}
|
|
125
|
+
return resolved;
|
|
126
|
+
}
|
|
127
|
+
function resolveEntity(entityID, provider, user) {
|
|
128
|
+
const entity = (provider.Entities ?? []).find(e => UUIDsEqual(e.ID, entityID));
|
|
129
|
+
if (!entity || entity.IncludeInAPI === false || entity.Status === 'Disabled' || !entity.GetUserPermisions(user).CanRead) {
|
|
130
|
+
throw new ExcelSourceError('That entity doesn\'t exist, or you don\'t have access to read it.');
|
|
131
|
+
}
|
|
132
|
+
const columns = entityDefaultColumns(entity.Fields);
|
|
133
|
+
if (columns.length === 0) {
|
|
134
|
+
throw new ExcelSourceError(`The entity "${entity.DisplayNameOrName}" has no columns to show.`);
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
Kind: 'Entity',
|
|
138
|
+
ID: entity.ID,
|
|
139
|
+
Name: entity.DisplayNameOrName,
|
|
140
|
+
EntityName: entity.Name,
|
|
141
|
+
Columns: columns,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/** The view's visible columns in display order, or the entity's default columns when it records none. */
|
|
145
|
+
function viewColumns(columns, fields) {
|
|
146
|
+
const visible = columns
|
|
147
|
+
.filter(c => c && !c.hidden && c.EntityField && !c.EntityField.IsBinaryFieldType)
|
|
148
|
+
.sort((a, b) => orderOf(a) - orderOf(b));
|
|
149
|
+
if (visible.length > 0) {
|
|
150
|
+
return visible.map(c => ({
|
|
151
|
+
Name: c.EntityField.Name,
|
|
152
|
+
Header: c.userDisplayName || c.DisplayName || c.EntityField.DisplayNameOrName || c.Name,
|
|
153
|
+
DataType: DataTypeForEntityField(c.EntityField),
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
156
|
+
return entityDefaultColumns(fields);
|
|
157
|
+
}
|
|
158
|
+
function entityDefaultColumns(fields) {
|
|
159
|
+
const nonBinary = fields.filter(f => !f.IsBinaryFieldType);
|
|
160
|
+
const defaults = nonBinary.filter(f => f.DefaultInView);
|
|
161
|
+
const chosen = defaults.length > 0
|
|
162
|
+
? defaults
|
|
163
|
+
: nonBinary.filter(f => !f.Name.startsWith('__mj_'));
|
|
164
|
+
const finalFields = chosen.length > 0 ? chosen : nonBinary;
|
|
165
|
+
return [...finalFields]
|
|
166
|
+
.sort((a, b) => a.Sequence - b.Sequence)
|
|
167
|
+
.map(f => ({ Name: f.Name, Header: f.DisplayNameOrName, DataType: DataTypeForEntityField(f) }));
|
|
168
|
+
}
|
|
169
|
+
function orderOf(column) {
|
|
170
|
+
return typeof column.orderIndex === 'number' ? column.orderIndex : Number.MAX_SAFE_INTEGER;
|
|
171
|
+
}
|
|
172
|
+
function resolveQuery(request, provider, user) {
|
|
173
|
+
// Roles-only check (QueryInfo.UserCanRun). No rows are read here; GetQueryData runs the full check on refresh.
|
|
174
|
+
const query = provider.Queries.find(q => UUIDsEqual(q.ID, request.ID));
|
|
175
|
+
if (!query || !query.UserCanRun(user)) {
|
|
176
|
+
throw new ExcelSourceError('That saved query doesn\'t exist, or you don\'t have access to it.');
|
|
177
|
+
}
|
|
178
|
+
const source = { Kind: 'Query', ID: query.ID, Name: query.Name, Columns: queryColumns(query.Fields) };
|
|
179
|
+
const parameters = checkParameters(query, request.Parameters);
|
|
180
|
+
if (parameters) {
|
|
181
|
+
source.Parameters = parameters;
|
|
182
|
+
}
|
|
183
|
+
return source;
|
|
184
|
+
}
|
|
185
|
+
function queryColumns(fields) {
|
|
186
|
+
return [...fields]
|
|
187
|
+
.sort((a, b) => (a.Sequence ?? 0) - (b.Sequence ?? 0))
|
|
188
|
+
.map(f => ({ Name: f.Name, Header: f.Name, DataType: DataTypeForSQLType(f.SQLBaseType) }));
|
|
189
|
+
}
|
|
190
|
+
/** Keeps only the query's own, caller-settable parameters, under their canonical names. */
|
|
191
|
+
function checkParameters(query, supplied) {
|
|
192
|
+
if (!supplied || Object.keys(supplied).length === 0) {
|
|
193
|
+
return undefined;
|
|
194
|
+
}
|
|
195
|
+
const result = {};
|
|
196
|
+
for (const [name, value] of Object.entries(supplied)) {
|
|
197
|
+
const parameter = findParameter(query.Parameters, name);
|
|
198
|
+
if (!parameter) {
|
|
199
|
+
throw new ExcelSourceError(`The query "${query.Name}" has no parameter "${name}".`);
|
|
200
|
+
}
|
|
201
|
+
if (parameter.IsServerSet) {
|
|
202
|
+
throw new ExcelSourceError(`The parameter "${parameter.Name}" of the query "${query.Name}" is set by the server and can't be supplied.`);
|
|
203
|
+
}
|
|
204
|
+
if (!isParameterValue(value)) {
|
|
205
|
+
throw new ExcelSourceError(`The value for the parameter "${parameter.Name}" isn't valid.`);
|
|
206
|
+
}
|
|
207
|
+
result[parameter.Name] = value;
|
|
208
|
+
}
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
function findParameter(parameters, name) {
|
|
212
|
+
const wanted = name.trim().toLowerCase();
|
|
213
|
+
return parameters.find(p => p.Name.trim().toLowerCase() === wanted);
|
|
214
|
+
}
|
|
215
|
+
function isParameterValue(value) {
|
|
216
|
+
if (value === null || typeof value === 'boolean') {
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
if (typeof value === 'number') {
|
|
220
|
+
return Number.isFinite(value);
|
|
221
|
+
}
|
|
222
|
+
if (typeof value === 'string') {
|
|
223
|
+
return value.length <= MAX_PARAMETER_TEXT;
|
|
224
|
+
}
|
|
225
|
+
return Array.isArray(value) && value.every(v => typeof v === 'string' && v.length <= MAX_PARAMETER_TEXT);
|
|
226
|
+
}
|
|
227
|
+
function isDateOnlySQLType(sqlType) {
|
|
228
|
+
return (sqlType ?? '').trim().toLowerCase() === 'date';
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=sources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sources.js","sourceRoot":"","sources":["../src/sources.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ExcelWorkbookManifest } from '@memberjunction/excel-addin';
|
|
2
|
+
/** How a workbook names the add-in for Office. */
|
|
3
|
+
export interface ConnectedWorkbookOptions {
|
|
4
|
+
AddinId: string;
|
|
5
|
+
Version: string;
|
|
6
|
+
Store: string;
|
|
7
|
+
StoreType: string;
|
|
8
|
+
}
|
|
9
|
+
/** The note written under each sheet's headings until the pane fills it. */
|
|
10
|
+
export declare const EXCEL_EMPTY_SHEET_NOTE = "Sign in with the MemberJunction add-in to load this data.";
|
|
11
|
+
export declare const WEB_EXTENSION_PART = "xl/webextensions/webextension1.xml";
|
|
12
|
+
export declare const TASKPANES_PART = "xl/webextensions/taskpanes.xml";
|
|
13
|
+
export declare const TASKPANES_RELS_PART = "xl/webextensions/_rels/taskpanes.xml.rels";
|
|
14
|
+
export declare const WEB_EXTENSION_CONTENT_TYPE = "application/vnd.ms-office.webextension+xml";
|
|
15
|
+
export declare const TASKPANES_CONTENT_TYPE = "application/vnd.ms-office.webextensiontaskpanes+xml";
|
|
16
|
+
export declare const TASKPANES_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/office/2011/relationships/webextensiontaskpanes";
|
|
17
|
+
/** Builds the workbook for a manifest whose sources are already resolved and checked. */
|
|
18
|
+
export declare function BuildConnectedWorkbook(manifest: ExcelWorkbookManifest, options: ConnectedWorkbookOptions): Promise<Buffer>;
|
|
19
|
+
/** Adds the parts that make Excel open the add-in with this file. */
|
|
20
|
+
export declare function AddWebExtensionParts(xlsx: Buffer, options: ConnectedWorkbookOptions): Promise<Buffer>;
|
|
21
|
+
//# sourceMappingURL=workbook-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workbook-builder.d.ts","sourceRoot":"","sources":["../src/workbook-builder.ts"],"names":[],"mappings":"AAqBA,OAAO,EAGH,qBAAqB,EAGxB,MAAM,6BAA6B,CAAC;AAGrC,kDAAkD;AAClD,MAAM,WAAW,wBAAwB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,4EAA4E;AAC5E,eAAO,MAAM,sBAAsB,8DAA8D,CAAC;AAElG,eAAO,MAAM,kBAAkB,uCAAuC,CAAC;AACvE,eAAO,MAAM,cAAc,mCAAmC,CAAC;AAC/D,eAAO,MAAM,mBAAmB,8CAA8C,CAAC;AAC/E,eAAO,MAAM,0BAA0B,+CAA+C,CAAC;AACvF,eAAO,MAAM,sBAAsB,wDAAwD,CAAC;AAC5F,eAAO,MAAM,2BAA2B,iFAAiF,CAAC;AAM1H,yFAAyF;AACzF,wBAAsB,sBAAsB,CAAC,QAAQ,EAAE,qBAAqB,EAAE,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,CAUhI;AAED,qEAAqE;AACrE,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,CAa3G"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Builds an Open in Excel workbook: headings and no rows, the source record, and the
|
|
3
|
+
* Office parts that open the add-in when the file opens.
|
|
4
|
+
*
|
|
5
|
+
* `exceljs` writes the sheets. It can't write Office web-extension parts, so the file is then
|
|
6
|
+
* reopened with `jszip` and four parts are added, the same ones Excel writes when a task pane is
|
|
7
|
+
* pinned to a document:
|
|
8
|
+
*
|
|
9
|
+
* - `xl/webextensions/webextension1.xml` names the add-in (its GUID, version, store and store type)
|
|
10
|
+
* and sets `Office.AutoShowTaskpaneWithDocument`, which opens the pane with the file;
|
|
11
|
+
* - `xl/webextensions/taskpanes.xml` docks that pane, through
|
|
12
|
+
* `xl/webextensions/_rels/taskpanes.xml.rels`;
|
|
13
|
+
* - an `[Content_Types].xml` override for each part, and the package relationship in `_rels/.rels`.
|
|
14
|
+
*
|
|
15
|
+
* The file carries no rows and no credential. Whoever opens it signs in and fills it as themselves.
|
|
16
|
+
*
|
|
17
|
+
* @module @memberjunction/excel-addin-server
|
|
18
|
+
*/
|
|
19
|
+
import { randomUUID } from 'node:crypto';
|
|
20
|
+
import ExcelJS from 'exceljs';
|
|
21
|
+
import JSZip from 'jszip';
|
|
22
|
+
import { EXCEL_SOURCES_SHEET_NAME, SplitManifestForCells, } from '@memberjunction/excel-addin';
|
|
23
|
+
import { EscapeXml } from './manifest-builder.js';
|
|
24
|
+
/** The note written under each sheet's headings until the pane fills it. */
|
|
25
|
+
export const EXCEL_EMPTY_SHEET_NOTE = 'Sign in with the MemberJunction add-in to load this data.';
|
|
26
|
+
export const WEB_EXTENSION_PART = 'xl/webextensions/webextension1.xml';
|
|
27
|
+
export const TASKPANES_PART = 'xl/webextensions/taskpanes.xml';
|
|
28
|
+
export const TASKPANES_RELS_PART = 'xl/webextensions/_rels/taskpanes.xml.rels';
|
|
29
|
+
export const WEB_EXTENSION_CONTENT_TYPE = 'application/vnd.ms-office.webextension+xml';
|
|
30
|
+
export const TASKPANES_CONTENT_TYPE = 'application/vnd.ms-office.webextensiontaskpanes+xml';
|
|
31
|
+
export const TASKPANES_RELATIONSHIP_TYPE = 'http://schemas.microsoft.com/office/2011/relationships/webextensiontaskpanes';
|
|
32
|
+
const WEB_EXTENSION_RELATIONSHIP_TYPE = 'http://schemas.microsoft.com/office/2011/relationships/webextension';
|
|
33
|
+
const ROOT_RELATIONSHIP_ID = 'rIdMJExcelAddinTaskpanes';
|
|
34
|
+
const MIN_COLUMN_WIDTH = 10;
|
|
35
|
+
const MAX_COLUMN_WIDTH = 50;
|
|
36
|
+
/** Builds the workbook for a manifest whose sources are already resolved and checked. */
|
|
37
|
+
export async function BuildConnectedWorkbook(manifest, options) {
|
|
38
|
+
const workbook = new ExcelJS.Workbook();
|
|
39
|
+
workbook.creator = 'MemberJunction';
|
|
40
|
+
workbook.created = new Date(manifest.GeneratedAt);
|
|
41
|
+
for (const source of manifest.Sources) {
|
|
42
|
+
addDataSheet(workbook, source);
|
|
43
|
+
}
|
|
44
|
+
addSourcesSheet(workbook, manifest);
|
|
45
|
+
const written = await workbook.xlsx.writeBuffer();
|
|
46
|
+
return AddWebExtensionParts(Buffer.from(written), options);
|
|
47
|
+
}
|
|
48
|
+
/** Adds the parts that make Excel open the add-in with this file. */
|
|
49
|
+
export async function AddWebExtensionParts(xlsx, options) {
|
|
50
|
+
const zip = await JSZip.loadAsync(xlsx);
|
|
51
|
+
zip.file(WEB_EXTENSION_PART, buildWebExtensionXml(options));
|
|
52
|
+
zip.file(TASKPANES_PART, TASKPANES_XML);
|
|
53
|
+
zip.file(TASKPANES_RELS_PART, TASKPANES_RELS_XML);
|
|
54
|
+
await updatePart(zip, '[Content_Types].xml', '</Types>', [
|
|
55
|
+
`<Override PartName="/${TASKPANES_PART}" ContentType="${TASKPANES_CONTENT_TYPE}"/>`,
|
|
56
|
+
`<Override PartName="/${WEB_EXTENSION_PART}" ContentType="${WEB_EXTENSION_CONTENT_TYPE}"/>`,
|
|
57
|
+
]);
|
|
58
|
+
await updatePart(zip, '_rels/.rels', '</Relationships>', [
|
|
59
|
+
`<Relationship Id="${ROOT_RELATIONSHIP_ID}" Type="${TASKPANES_RELATIONSHIP_TYPE}" Target="${TASKPANES_PART}"/>`,
|
|
60
|
+
]);
|
|
61
|
+
return zip.generateAsync({ type: 'nodebuffer', compression: 'DEFLATE' });
|
|
62
|
+
}
|
|
63
|
+
function addDataSheet(workbook, source) {
|
|
64
|
+
const sheet = workbook.addWorksheet(source.SheetName, { views: [{ state: 'frozen', ySplit: 1 }] });
|
|
65
|
+
if (source.Columns.length > 0) {
|
|
66
|
+
sheet.columns = source.Columns.map(c => ({ header: c.Header, key: c.Name, width: columnWidth(c) }));
|
|
67
|
+
sheet.getRow(1).font = { bold: true };
|
|
68
|
+
}
|
|
69
|
+
const note = sheet.getCell(source.Columns.length > 0 ? 'A2' : 'A1');
|
|
70
|
+
note.value = EXCEL_EMPTY_SHEET_NOTE;
|
|
71
|
+
note.font = { italic: true, color: { argb: 'FF6B7280' } };
|
|
72
|
+
}
|
|
73
|
+
function addSourcesSheet(workbook, manifest) {
|
|
74
|
+
const sheet = workbook.addWorksheet(EXCEL_SOURCES_SHEET_NAME, { state: 'veryHidden' });
|
|
75
|
+
SplitManifestForCells(manifest).forEach((chunk, i) => {
|
|
76
|
+
sheet.getCell(i + 1, 1).value = chunk;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function columnWidth(column) {
|
|
80
|
+
const base = column.DataType === 'DateTime' ? 20 : column.DataType === 'Date' ? 12 : column.Header.length + 2;
|
|
81
|
+
return Math.min(MAX_COLUMN_WIDTH, Math.max(MIN_COLUMN_WIDTH, base));
|
|
82
|
+
}
|
|
83
|
+
function buildWebExtensionXml(options) {
|
|
84
|
+
return [
|
|
85
|
+
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>',
|
|
86
|
+
`<we:webextension xmlns:we="http://schemas.microsoft.com/office/webextensions/webextension/2010/11" id="{${randomUUID().toUpperCase()}}">`,
|
|
87
|
+
`<we:reference id="${EscapeXml(options.AddinId)}" version="${EscapeXml(options.Version)}" store="${EscapeXml(options.Store)}" storeType="${EscapeXml(options.StoreType)}"/>`,
|
|
88
|
+
'<we:alternateReferences/>',
|
|
89
|
+
'<we:properties><we:property name="Office.AutoShowTaskpaneWithDocument" value="true"/></we:properties>',
|
|
90
|
+
'<we:bindings/>',
|
|
91
|
+
'<we:snapshot xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"/>',
|
|
92
|
+
'</we:webextension>',
|
|
93
|
+
].join('');
|
|
94
|
+
}
|
|
95
|
+
const TASKPANES_XML = [
|
|
96
|
+
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>',
|
|
97
|
+
'<wetp:taskpanes xmlns:wetp="http://schemas.microsoft.com/office/webextensions/taskpanes/2010/11">',
|
|
98
|
+
'<wetp:taskpane dockstate="right" visibility="1" width="350" row="4">',
|
|
99
|
+
'<wetp:webextensionref xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" r:id="rId1"/>',
|
|
100
|
+
'</wetp:taskpane>',
|
|
101
|
+
'</wetp:taskpanes>',
|
|
102
|
+
].join('');
|
|
103
|
+
const TASKPANES_RELS_XML = [
|
|
104
|
+
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>',
|
|
105
|
+
'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">',
|
|
106
|
+
`<Relationship Id="rId1" Type="${WEB_EXTENSION_RELATIONSHIP_TYPE}" Target="webextension1.xml"/>`,
|
|
107
|
+
'</Relationships>',
|
|
108
|
+
].join('');
|
|
109
|
+
/** Inserts `additions` before `closingTag` in a part exceljs wrote. Throws if the part is missing. */
|
|
110
|
+
async function updatePart(zip, path, closingTag, additions) {
|
|
111
|
+
const part = zip.file(path);
|
|
112
|
+
if (!part) {
|
|
113
|
+
throw new Error(`The workbook has no ${path} part.`);
|
|
114
|
+
}
|
|
115
|
+
const xml = await part.async('string');
|
|
116
|
+
const at = xml.lastIndexOf(closingTag);
|
|
117
|
+
if (at < 0) {
|
|
118
|
+
throw new Error(`The workbook's ${path} part is malformed.`);
|
|
119
|
+
}
|
|
120
|
+
zip.file(path, xml.slice(0, at) + additions.join('') + xml.slice(at));
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=workbook-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workbook-builder.js","sourceRoot":"","sources":["../src/workbook-builder.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/excel-addin-server",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
"version": "6.2.0-edge.7",
|
|
4
|
+
"description": "MemberJunction: the Excel add-in's server half - a Server Extension that serves the add-in to Excel from each MJ host, the add-in manifest and connected-workbook builders, and the server bodies of the ExcelAddin.* Remote Operations",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"files": [
|
|
9
|
+
"/dist"
|
|
10
|
+
],
|
|
11
|
+
"author": "MemberJunction.com",
|
|
12
|
+
"license": "BUSL-1.1",
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@memberjunction/api-keys": "6.2.0-edge.7",
|
|
15
|
+
"@memberjunction/api-keys-base": "6.2.0-edge.7",
|
|
16
|
+
"@memberjunction/core": "6.2.0-edge.7",
|
|
17
|
+
"@memberjunction/core-entities": "6.2.0-edge.7",
|
|
18
|
+
"@memberjunction/excel-addin": "6.2.0-edge.7",
|
|
19
|
+
"@memberjunction/global": "6.2.0-edge.7",
|
|
20
|
+
"@memberjunction/server-extensions-core": "6.2.0-edge.7",
|
|
21
|
+
"exceljs": "^4.4.0",
|
|
22
|
+
"express": "^5.2.1",
|
|
23
|
+
"jszip": "^3.10.1"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/express": "^5.0.6",
|
|
27
|
+
"typescript": "^5.9.3",
|
|
28
|
+
"vitest": "^3.1.1",
|
|
29
|
+
"vite-tsconfig-paths": "^5.1.4"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/MemberJunction/MJ"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc && tsc-alias -f",
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"test:watch": "vitest",
|
|
39
|
+
"test:coverage": "vitest run --coverage"
|
|
40
|
+
}
|
|
41
|
+
}
|