@adaptabletools/adaptable-plugin-ipushpull-cjs 22.0.1 → 22.0.3

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.
@@ -8,7 +8,7 @@ const React = tslib_1.__importStar(require("react"));
8
8
  const ObjectFactory_1 = tslib_1.__importDefault(require("@adaptabletools/adaptable-cjs/src/Utilities/ObjectFactory"));
9
9
  const StringExtensions_1 = require("@adaptabletools/adaptable-cjs/src/Utilities/Extensions/StringExtensions");
10
10
  const Flex_1 = require("@adaptabletools/adaptable-cjs/src/components/Flex");
11
- const DropdownButton_1 = tslib_1.__importDefault(require("@adaptabletools/adaptable-cjs/src/components/DropdownButton"));
11
+ const Select_1 = require("@adaptabletools/adaptable-cjs/src/components/Select");
12
12
  const ButtonExport_1 = require("@adaptabletools/adaptable-cjs/src/View/Components/Buttons/ButtonExport");
13
13
  const ButtonPause_1 = require("@adaptabletools/adaptable-cjs/src/View/Components/Buttons/ButtonPause");
14
14
  const ButtonPlay_1 = require("@adaptabletools/adaptable-cjs/src/View/Components/Buttons/ButtonPlay");
@@ -66,58 +66,42 @@ const IPushPullViewPanelComponent = (props) => {
66
66
  let allReports = systemReports
67
67
  .filter((s) => props.api.exportApi.internalApi.isSystemReportActive(s))
68
68
  .concat(props.Reports.map((r) => r.Name));
69
- let availableReports = allReports.map((report) => {
70
- return {
71
- label: report,
72
- value: report,
73
- onClick: () => onSelectedReportChanged(report),
74
- };
75
- });
76
- let availableFolders = props.IPushPullDomainsPages?.map((iPushPullDomain) => {
77
- return {
78
- label: iPushPullDomain.Name,
79
- value: iPushPullDomain.Name,
80
- onClick: () => onFolderChanged(iPushPullDomain.Name),
81
- };
82
- }) ?? [];
83
- let availablePages = props.CurrentIPushPullAvailablePages?.map((page) => {
84
- return {
85
- label: page,
86
- value: page,
87
- onClick: () => onPageChanged(page),
88
- };
89
- }) ?? [];
90
- // this is clearly ridiculous!
91
- // im getting tired...
92
- let isCompletedReport = StringExtensions_1.StringExtensions.IsNotNullOrEmpty(props.CurrentIPushPullReportName) &&
93
- StringExtensions_1.StringExtensions.IsNotNullOrEmpty(props.CurrentIPushPullFolder) &&
94
- StringExtensions_1.StringExtensions.IsNotNullOrEmpty(props.CurrentIPushPullPage);
69
+ let availableReports = allReports.map((report) => ({
70
+ label: report,
71
+ value: report,
72
+ }));
73
+ let availableFolders = props.IPushPullDomainsPages?.map((iPushPullDomain) => ({
74
+ label: iPushPullDomain.Name,
75
+ value: iPushPullDomain.Name,
76
+ })) ?? [];
77
+ let availablePages = props.CurrentIPushPullAvailablePages?.map((page) => ({
78
+ label: page,
79
+ value: page,
80
+ })) ?? [];
81
+ let hasReport = StringExtensions_1.StringExtensions.IsNotNullOrEmpty(props.CurrentIPushPullReportName);
82
+ let hasFolder = StringExtensions_1.StringExtensions.IsNotNullOrEmpty(props.CurrentIPushPullFolder);
83
+ let hasPage = StringExtensions_1.StringExtensions.IsNotNullOrEmpty(props.CurrentIPushPullPage);
84
+ let isCompletedReport = hasReport && hasFolder && hasPage;
95
85
  let isLiveIPushPullReport = isCompletedReport &&
96
86
  props.CurrentLiveIPushPullReport &&
97
87
  props.CurrentIPushPullReportName == props.CurrentLiveIPushPullReport.ReportName &&
98
88
  props.CurrentIPushPullFolder == props.CurrentLiveIPushPullReport.Folder &&
99
89
  props.CurrentIPushPullPage == props.CurrentLiveIPushPullReport.Page;
100
90
  const elementType = props.viewType === 'Toolbar' ? 'DashboardToolbar' : 'ToolPanel';
101
- return props.IsIPushPullRunning ? (React.createElement(Flex_1.Flex, { flexDirection: "row", className: `ab-${elementType}__IPushPull__wrap`, flexWrap: props.viewType === 'ToolPanel' ? 'wrap' : 'nowrap' },
102
- React.createElement(Flex_1.Flex, null,
103
- React.createElement(DropdownButton_1.default, { disabled: allReports.length == 0 || isLiveIPushPullReport, items: availableReports, columns: ['label'], className: `ab-${elementType}__IPushPull__select twa:min-w-[140px] twa:text-0 twa:mr-2`, onClear: () => onSelectedReportChanged(''), showClearButton: StringExtensions_1.StringExtensions.IsNotNullOrEmpty(props.CurrentIPushPullReportName), variant: "outlined" }, StringExtensions_1.StringExtensions.IsNotNullOrEmpty(props.CurrentIPushPullReportName)
104
- ? props.CurrentIPushPullReportName
105
- : 'Select Report')),
106
- React.createElement(Flex_1.Flex, null,
107
- React.createElement(DropdownButton_1.default, { disabled: allReports.length == 0 || isLiveIPushPullReport, items: availableFolders, columns: ['label'], className: `ab-${elementType}__IPushPull__select twa:min-w-[140px] twa:text-0 twa:mr-2`, onClear: () => onFolderChanged(''), showClearButton: StringExtensions_1.StringExtensions.IsNotNullOrEmpty(props.CurrentIPushPullFolder), variant: "outlined" }, StringExtensions_1.StringExtensions.IsNotNullOrEmpty(props.CurrentIPushPullFolder)
108
- ? props.CurrentIPushPullFolder
109
- : 'Select Folder')),
110
- React.createElement(Flex_1.Flex, null,
111
- React.createElement(DropdownButton_1.default, { disabled: allReports.length == 0 || isLiveIPushPullReport, items: availablePages, columns: ['label'], className: `ab-${elementType}__IPushPull__select twa:min-w-[140px] twa:text-0 twa:mr-2`, onClear: () => onPageChanged(''), showClearButton: StringExtensions_1.StringExtensions.IsNotNullOrEmpty(props.CurrentIPushPullPage), variant: "outlined" }, StringExtensions_1.StringExtensions.IsNotNullOrEmpty(props.CurrentIPushPullPage)
112
- ? props.CurrentIPushPullPage
113
- : 'Select Page')),
114
- React.createElement(Flex_1.Flex, { className: "twa:min-w-[148px]" },
115
- React.createElement(ButtonExport_1.ButtonExport, { className: `ab-${elementType}__IPushPull__export twa:ml-1`, onClick: () => onIPushPullSendSnapshot(), tooltip: "Send Snapshot to ipushpull", disabled: isLiveIPushPullReport || !isCompletedReport, accessLevel: props.accessLevel }),
116
- true ? (React.createElement(ButtonPause_1.ButtonPause, { className: `ab-${elementType}__IPushPull__pause twa:ml-1 twa:fill-red-500`, onClick: () => props.onIPushPullStopLiveData(), tooltip: "Stop sync with ipushpull", disabled: !isLiveIPushPullReport, accessLevel: props.accessLevel })) : (React.createElement(ButtonPlay_1.ButtonPlay, { className: `ab-${elementType}__IPushPull__play twa:ml-1`, onClick: () => onIPushPullStartLiveData(), tooltip: "Start sync with ipushpull", disabled: isLiveIPushPullReport || !isCompletedReport, accessLevel: props.accessLevel })),
117
- isCompletedReport && (React.createElement(Flex_1.Flex, { className: (0, join_1.default)(props.accessLevel == 'ReadOnly' ? GeneralConstants.READ_ONLY_STYLE : '', `ab-${elementType}__IPushPull__controls`), alignItems: "stretch" }, props.api.entitlementApi.isModuleFullEntitlement('Schedule') && (React.createElement(ButtonSchedule_1.ButtonSchedule, { className: `ab-${elementType}__IPushPull__schedule twa:ml-1`, onClick: () => onNewIPushPullSchedule(), tooltip: "Schedule", disabled: isLiveIPushPullReport || !isCompletedReport, accessLevel: props.accessLevel })))),
118
- ' ',
119
- React.createElement(ButtonNewPage_1.ButtonNewPage, { className: `ab-${elementType}__IPushPull__newpage twa:ml-1`, onClick: () => props.onShowAddIPushPullPage(), tooltip: "New Page", disabled: isLiveIPushPullReport, accessLevel: props.accessLevel }),
120
- React.createElement(ButtonLogout_1.ButtonLogout, { className: `ab-${elementType}__IPushPull__logout twa:ml-1`, onClick: () => getIPPApi().logoutFromIPushPull(), tooltip: "Logout", disabled: isLiveIPushPullReport, accessLevel: props.accessLevel })))) : (React.createElement(ButtonLogin_1.ButtonLogin, { className: `ab-${elementType}__IPushPull__login twa:ml-1`, onClick: () => props.onShowIPushPullLogin(), tooltip: "Login to ipushpull", accessLevel: props.accessLevel },
91
+ return props.IsIPushPullRunning ? (React.createElement(Flex_1.Flex, { flexDirection: "row", className: `ab-${elementType}__IPushPull__wrap twa:gap-1`, flexWrap: props.viewType === 'ToolPanel' ? 'wrap' : 'nowrap' },
92
+ React.createElement(Flex_1.Flex, { className: "twa:min-w-[140px]" },
93
+ React.createElement(Select_1.Select, { disabled: allReports.length == 0 || isLiveIPushPullReport, options: availableReports, className: `ab-${elementType}__IPushPull__select twa:w-full`, placeholder: "Select Report", onChange: (reportName) => onSelectedReportChanged(reportName), value: props.CurrentIPushPullReportName, isClearable: true })),
94
+ React.createElement(Flex_1.Flex, { className: "twa:min-w-[140px]" },
95
+ React.createElement(Select_1.Select, { disabled: !hasReport || isLiveIPushPullReport, options: availableFolders, className: `ab-${elementType}__IPushPull__select twa:w-full`, placeholder: "Select Folder", onChange: (folder) => onFolderChanged(folder), value: props.CurrentIPushPullFolder, isClearable: true })),
96
+ React.createElement(Flex_1.Flex, { className: "twa:min-w-[140px]" },
97
+ React.createElement(Select_1.Select, { disabled: !hasFolder || isLiveIPushPullReport, options: availablePages, className: `ab-${elementType}__IPushPull__select twa:w-full`, placeholder: "Select Page", onChange: (page) => onPageChanged(page), value: props.CurrentIPushPullPage, isClearable: true })),
98
+ React.createElement(Flex_1.Flex, { className: (0, join_1.default)(props.accessLevel == 'ReadOnly' ? GeneralConstants.READ_ONLY_STYLE : '', `ab-${elementType}__IPushPull__controls twa:w-full`) },
99
+ React.createElement(Flex_1.Flex, null,
100
+ React.createElement(ButtonExport_1.ButtonExport, { className: `ab-${elementType}__IPushPull__export`, onClick: () => onIPushPullSendSnapshot(), tooltip: "Send Snapshot to ipushpull", disabled: isLiveIPushPullReport || !isCompletedReport, accessLevel: props.accessLevel }),
101
+ isLiveIPushPullReport ? (React.createElement(ButtonPause_1.ButtonPause, { className: `ab-${elementType}__IPushPull__pause twa:fill-red-500`, onClick: () => props.onIPushPullStopLiveData(), tooltip: "Stop sync with ipushpull", disabled: !isLiveIPushPullReport, accessLevel: props.accessLevel })) : (React.createElement(ButtonPlay_1.ButtonPlay, { className: `ab-${elementType}__IPushPull__play`, onClick: () => onIPushPullStartLiveData(), tooltip: "Start sync with ipushpull", disabled: isLiveIPushPullReport || !isCompletedReport, accessLevel: props.accessLevel })),
102
+ props.api.entitlementApi.isModuleFullEntitlement('Schedule') && (React.createElement(ButtonSchedule_1.ButtonSchedule, { className: `ab-${elementType}__IPushPull__schedule`, onClick: () => onNewIPushPullSchedule(), tooltip: "Schedule", disabled: isLiveIPushPullReport || !isCompletedReport, accessLevel: props.accessLevel })),
103
+ React.createElement(ButtonNewPage_1.ButtonNewPage, { className: `ab-${elementType}__IPushPull__newpage`, onClick: () => props.onShowAddIPushPullPage(), tooltip: "New Page", disabled: !hasFolder || isLiveIPushPullReport, accessLevel: props.accessLevel }),
104
+ React.createElement(ButtonLogout_1.ButtonLogout, { className: `ab-${elementType}__IPushPull__logout`, onClick: () => getIPPApi().logoutFromIPushPull(), tooltip: "Logout", disabled: isLiveIPushPullReport, accessLevel: props.accessLevel }))))) : (React.createElement(ButtonLogin_1.ButtonLogin, { className: `ab-${elementType}__IPushPull__login twa:ml-1`, onClick: () => props.onShowIPushPullLogin(), tooltip: "Login to ipushpull", accessLevel: props.accessLevel },
121
105
  ' ',
122
106
  "Login"));
123
107
  };
package/src/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { AdaptablePlugin } from "@adaptabletools/adaptable-cjs";
1
+ import { AdaptablePlugin } from "@adaptabletools/adaptable-cjs/types";
2
2
  import type { Middleware } from 'redux';
3
3
  import * as Redux from 'redux';
4
4
  import { IPushPullState } from "@adaptabletools/adaptable-cjs/src/AdaptableState/IPushPullState";
5
5
  import { IPushPullApi } from "@adaptabletools/adaptable-cjs/src/Api/IPushPullApi";
6
- import { IPushPullPluginOptions } from "@adaptabletools/adaptable-cjs/src/AdaptableOptions/IPushPullPluginOptions";
6
+ import { IPushPullPluginOptions } from './IPushPullPluginOptions';
7
7
  import { IAdaptable } from "@adaptabletools/adaptable-cjs/src/AdaptableInterfaces/IAdaptable";
8
8
  declare class IPushPullPlugin extends AdaptablePlugin {
9
9
  options: IPushPullPluginOptions;
@@ -13,10 +13,11 @@ declare class IPushPullPlugin extends AdaptablePlugin {
13
13
  constructor(options?: IPushPullPluginOptions);
14
14
  afterInitApi(adaptable: IAdaptable): void;
15
15
  rootReducer: (rootReducer: any) => {
16
- System: (state: IPushPullState, action: Redux.Action) => IPushPullState;
16
+ Internal: (state: IPushPullState, action: Redux.Action) => IPushPullState;
17
17
  };
18
18
  reduxMiddleware: (adaptable: IAdaptable) => Middleware;
19
19
  afterInitStore(adaptable: IAdaptable): void;
20
20
  }
21
- declare const _default: (options?: IPushPullPluginOptions) => IPushPullPlugin;
22
- export default _default;
21
+ export type { IPushPullPluginOptions, IPushPullConfig } from './IPushPullPluginOptions';
22
+ export declare const ipushpullPlugin: (options?: IPushPullPluginOptions) => IPushPullPlugin;
23
+ export default ipushpullPlugin;
package/src/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ipushpullPlugin = void 0;
3
4
  const tslib_1 = require("tslib");
4
- const adaptable_1 = require("@adaptabletools/adaptable-cjs");
5
+ const types_1 = require("@adaptabletools/adaptable-cjs/types");
5
6
  const env_1 = tslib_1.__importDefault(require("./env"));
6
7
  const package_json_1 = tslib_1.__importDefault(require("../package.json"));
7
8
  const package_json_2 = tslib_1.__importDefault(require("@adaptabletools/adaptable-cjs/package.json"));
@@ -11,8 +12,8 @@ const PopupRedux = tslib_1.__importStar(require("@adaptabletools/adaptable-cjs/s
11
12
  const AdaptableViewFactory_1 = require("@adaptabletools/adaptable-cjs/src/View/AdaptableViewFactory");
12
13
  const PushPullModule_1 = require("./Module/PushPullModule");
13
14
  const IPushPullApiImpl_1 = require("./IPushPullApiImpl");
14
- const PushPullService_1 = require("./Utilities/Services/PushPullService");
15
- const ipushpull_js_1 = tslib_1.__importDefault(require("ipushpull-js"));
15
+ const IPushPullService_1 = require("./Utilities/Services/IPushPullService");
16
+ const ipushpull_client_1 = require("./ipushpull-client");
16
17
  const IPushPullRedux_1 = require("./Redux/ActionReducers/IPushPullRedux");
17
18
  const IPushPullLoginPopup_1 = require("./View/IPushPullLoginPopup");
18
19
  const IPushPullAddPagePopup_1 = require("./View/IPushPullAddPagePopup");
@@ -25,70 +26,60 @@ const suffix = name.endsWith('-cjs') ? '-cjs' : '';
25
26
  if (version !== coreVersion) {
26
27
  console.warn(`Version mismatch: "@adaptabletools/adaptable-plugin-ipushpull${suffix}" (v${version}) and "@adaptabletools/adaptable${suffix}" (v${coreVersion}) have different versions. They should be the exact same version.`);
27
28
  }
29
+ const DEFAULT_API_URL = 'https://test.ipushpull.com/api/1.0';
28
30
  const getApiKey = () => {
29
- let key = env_1.default.IPUSHPULL_API_KEY; // need to make sure that is always there
30
- return key;
31
+ return env_1.default.IPUSHPULL_API_KEY || '';
31
32
  };
32
33
  const getApiSecret = () => {
33
- let secret = env_1.default.IPUSHPULL_API_SECRET; // need to make sure that is always there
34
- return secret;
34
+ return env_1.default.IPUSHPULL_API_SECRET || '';
35
35
  };
36
36
  const defaultOptions = {
37
37
  ippConfig: {
38
- api_secret: getApiSecret() || '',
39
- api_key: getApiKey() || '',
40
- api_url: 'https://www.ipushpull.com/api/1.0',
41
- ws_url: 'https://www.ipushpull.com',
42
- web_url: 'https://www.ipushpull.com',
43
- docs_url: 'https://docs.ipushpull.com',
44
- storage_prefix: 'ipp_local',
45
- transport: 'polling',
46
- hsts: false, // strict cors policy
38
+ api_key: getApiKey(),
39
+ api_secret: getApiSecret(),
40
+ api_url: DEFAULT_API_URL,
47
41
  },
48
42
  autoLogin: false,
49
43
  throttleTime: 2000,
50
44
  includeSystemReports: true,
51
45
  };
52
- class IPushPullPlugin extends adaptable_1.AdaptablePlugin {
46
+ class IPushPullPlugin extends types_1.AdaptablePlugin {
53
47
  pluginId = 'ipushpull';
54
48
  iPushPullApi;
55
49
  PushPullService;
56
50
  constructor(options) {
57
51
  super(options);
52
+ const defaults = defaultOptions.ippConfig;
53
+ const userConfig = options?.ippConfig;
58
54
  const ippConfig = {
59
- ...defaultOptions.ippConfig,
60
- ...(options || {}).ippConfig,
55
+ api_url: userConfig?.api_url ?? defaults.api_url ?? DEFAULT_API_URL,
56
+ api_key: userConfig?.api_key || defaults.api_key,
57
+ api_secret: userConfig?.api_secret || defaults.api_secret,
61
58
  };
62
- if (!ippConfig.api_key) {
63
- ippConfig.api_key = defaultOptions.ippConfig.api_key;
64
- }
65
- if (!ippConfig.api_secret) {
66
- ippConfig.api_secret = defaultOptions.ippConfig.api_secret;
67
- }
68
59
  this.options = {
69
60
  ...defaultOptions,
70
61
  ...options,
71
62
  ippConfig,
72
63
  };
73
- /**
74
- * Contains the objects required to export (snapshot or live) data to ipushpull from AdapTable.
75
- *
76
- * Includes ipushpull config and objects and, optionally, any ipushpull Reports (including schedules).
77
- */
78
- // IPushPull?: IPushPullState;
79
- ipushpull_js_1.default.config.set(this.options.ippConfig);
80
64
  }
81
65
  afterInitApi(adaptable) {
66
+ const config = this.options.ippConfig;
67
+ const client = new ipushpull_client_1.IPushPullClient({
68
+ api_url: config.api_url ?? DEFAULT_API_URL,
69
+ api_key: config.api_key,
70
+ api_secret: config.api_secret,
71
+ });
82
72
  this.iPushPullApi = new IPushPullApiImpl_1.IPushPullApiImpl(adaptable, this.options);
83
- this.PushPullService = new PushPullService_1.PushPullService(adaptable);
84
- this.iPushPullApi.setIPushPullInstance(ipushpull_js_1.default);
73
+ this.PushPullService = new IPushPullService_1.IPushPullService(adaptable, this.options.cellStyles);
74
+ this.iPushPullApi.setIPushPullInstance(client);
85
75
  this.registerProperty('api', () => this.iPushPullApi);
86
76
  this.registerProperty('service', () => this.PushPullService);
87
77
  }
78
+ // FIXME AFL improve typing
88
79
  rootReducer = (rootReducer) => {
89
80
  return {
90
- System: (state, action) => {
91
- let augmentedState = rootReducer.System(state, action);
81
+ Internal: (state, action) => {
82
+ let augmentedState = rootReducer.Internal(state, action);
92
83
  if (!state) {
93
84
  // required for store initialization
94
85
  // (idiomatic way of default parameter value in reducer is not feasible because the passed argument is already initialized by the System reducer)
@@ -145,7 +136,7 @@ class IPushPullPlugin extends adaptable_1.AdaptablePlugin {
145
136
  return next(action);
146
137
  }
147
138
  case PluginsRedux_1.IPUSHPULL_DOMAIN_PAGES_SET: {
148
- //refresh the available pages
139
+ const result = next(action);
149
140
  const currentFolder = middlewareAPI.getState().Internal.IPushPullCurrentFolder;
150
141
  const isFolderValid = StringExtensions_1.default.IsNotNullOrEmpty(currentFolder);
151
142
  if (isFolderValid) {
@@ -154,7 +145,7 @@ class IPushPullPlugin extends adaptable_1.AdaptablePlugin {
154
145
  .getPagesForIPushPullDomain(currentFolder);
155
146
  middlewareAPI.dispatch((0, IPushPullRedux_1.IPushPullSetCurrentAvailablePages)(availablePages));
156
147
  }
157
- return next(action);
148
+ return result;
158
149
  }
159
150
  default: {
160
151
  return next(action);
@@ -170,4 +161,6 @@ class IPushPullPlugin extends adaptable_1.AdaptablePlugin {
170
161
  AdaptableViewFactory_1.AdaptableViewPanelFactory.set(ModuleConstants_1.IPushPullModuleId, IPushPullViewPanel_1.IPushPullViewPanelControl);
171
162
  }
172
163
  }
173
- exports.default = (options) => new IPushPullPlugin(options);
164
+ const ipushpullPlugin = (options) => new IPushPullPlugin(options);
165
+ exports.ipushpullPlugin = ipushpullPlugin;
166
+ exports.default = exports.ipushpullPlugin;
@@ -0,0 +1,28 @@
1
+ import { IPushPullClientConfig, IPushPullTokens, IPushPullDomainAccessInfo, IPushPullPageContentPayload, IPushPullPageContentResponse, IPushPullCellStyle } from './types';
2
+ export declare class IPushPullClient {
3
+ private config;
4
+ private tokens;
5
+ private refreshPromise;
6
+ constructor(config: IPushPullClientConfig);
7
+ private getBasicAuthHeader;
8
+ private buildOAuthBody;
9
+ login(username: string, password: string): Promise<IPushPullTokens>;
10
+ refreshToken(): Promise<IPushPullTokens>;
11
+ private doRefreshToken;
12
+ logout(): Promise<void>;
13
+ getDomainsAndPages(): Promise<IPushPullDomainAccessInfo[]>;
14
+ getPageContent(folderId: number, pageId: number): Promise<any>;
15
+ updatePageContent(folderId: number, pageId: number, payload: IPushPullPageContentPayload): Promise<IPushPullPageContentResponse>;
16
+ createPage(folderId: number, pageName: string, description?: string): Promise<any>;
17
+ isAuthenticated(): boolean;
18
+ private fetchWithAuth;
19
+ }
20
+ /**
21
+ * Converts per-cell data (array of rows, each cell being { value, formatted_value, style })
22
+ * into the official ipushpull page content format with deduplicated styles.
23
+ */
24
+ export declare function buildPageContentPayload(cellData: Array<Array<{
25
+ value: any;
26
+ formatted_value: any;
27
+ style: IPushPullCellStyle;
28
+ }>>): IPushPullPageContentPayload;
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IPushPullClient = void 0;
4
+ exports.buildPageContentPayload = buildPageContentPayload;
5
+ class IPushPullClient {
6
+ config;
7
+ tokens = null;
8
+ refreshPromise = null;
9
+ constructor(config) {
10
+ this.config = config;
11
+ }
12
+ getBasicAuthHeader() {
13
+ const credentials = `${this.config.api_key}:${this.config.api_secret}`;
14
+ return `Basic ${btoa(credentials)}`;
15
+ }
16
+ buildOAuthBody(params) {
17
+ return Object.entries(params)
18
+ .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
19
+ .join('&');
20
+ }
21
+ async login(username, password) {
22
+ const url = `${this.config.api_url}/oauth/token/`;
23
+ const body = this.buildOAuthBody({
24
+ grant_type: 'password',
25
+ username,
26
+ password,
27
+ });
28
+ const response = await fetch(url, {
29
+ method: 'POST',
30
+ headers: {
31
+ 'Content-Type': 'application/x-www-form-urlencoded',
32
+ Authorization: this.getBasicAuthHeader(),
33
+ },
34
+ body,
35
+ });
36
+ if (!response.ok) {
37
+ const errorData = await response.json().catch(() => ({}));
38
+ const message = errorData.error_description || errorData.error || response.statusText;
39
+ const err = new Error(message);
40
+ err.data = errorData;
41
+ throw err;
42
+ }
43
+ this.tokens = await response.json();
44
+ return this.tokens;
45
+ }
46
+ async refreshToken() {
47
+ if (!this.tokens?.refresh_token) {
48
+ throw new Error('No refresh token available. Please login first.');
49
+ }
50
+ // Deduplicate concurrent refresh attempts
51
+ if (this.refreshPromise) {
52
+ return this.refreshPromise;
53
+ }
54
+ this.refreshPromise = this.doRefreshToken();
55
+ try {
56
+ const result = await this.refreshPromise;
57
+ return result;
58
+ }
59
+ finally {
60
+ this.refreshPromise = null;
61
+ }
62
+ }
63
+ async doRefreshToken() {
64
+ const url = `${this.config.api_url}/oauth/token/`;
65
+ const body = this.buildOAuthBody({
66
+ grant_type: 'refresh_token',
67
+ refresh_token: this.tokens.refresh_token,
68
+ });
69
+ const response = await fetch(url, {
70
+ method: 'POST',
71
+ headers: {
72
+ 'Content-Type': 'application/x-www-form-urlencoded',
73
+ Authorization: this.getBasicAuthHeader(),
74
+ },
75
+ body,
76
+ });
77
+ if (!response.ok) {
78
+ this.tokens = null;
79
+ const errorData = await response.json().catch(() => ({}));
80
+ throw new Error(errorData.error_description || errorData.error || 'Token refresh failed');
81
+ }
82
+ this.tokens = await response.json();
83
+ return this.tokens;
84
+ }
85
+ async logout() {
86
+ if (!this.tokens?.access_token) {
87
+ return;
88
+ }
89
+ const url = `${this.config.api_url}/oauth/logout/`;
90
+ await fetch(url, {
91
+ method: 'POST',
92
+ headers: {
93
+ Authorization: `Bearer ${this.tokens.access_token}`,
94
+ },
95
+ });
96
+ this.tokens = null;
97
+ }
98
+ async getDomainsAndPages() {
99
+ const url = `${this.config.api_url}/domain_page_access`;
100
+ const response = await this.fetchWithAuth(url);
101
+ const data = await response.json();
102
+ return (data.domains ?? data).map((domain) => ({
103
+ id: domain.id,
104
+ name: domain.name,
105
+ pages: (domain.current_user_domain_page_access?.pages ?? domain.pages ?? []).map((page) => ({
106
+ id: page.id,
107
+ name: page.name,
108
+ special_page_type: page.special_page_type ?? 0,
109
+ write_access: page.write_access ?? false,
110
+ })),
111
+ }));
112
+ }
113
+ async getPageContent(folderId, pageId) {
114
+ const baseUrl = this.config.api_url.replace(/\/api\/1\.0\/?$/, '');
115
+ const url = `${baseUrl}/api/2.0/domains/id/${folderId}/page_content/id/${pageId}/`;
116
+ const response = await this.fetchWithAuth(url);
117
+ return response.json();
118
+ }
119
+ async updatePageContent(folderId, pageId, payload) {
120
+ const baseUrl = this.config.api_url.replace(/\/api\/1\.0\/?$/, '');
121
+ const url = `${baseUrl}/api/2.0/domains/id/${folderId}/page_content/id/${pageId}/`;
122
+ const response = await this.fetchWithAuth(url, {
123
+ method: 'PUT',
124
+ headers: { 'Content-Type': 'application/json' },
125
+ body: JSON.stringify(payload),
126
+ });
127
+ return response.json();
128
+ }
129
+ async createPage(folderId, pageName, description) {
130
+ const url = `${this.config.api_url}/domains/${folderId}/pages/`;
131
+ const response = await this.fetchWithAuth(url, {
132
+ method: 'POST',
133
+ headers: { 'Content-Type': 'application/json' },
134
+ body: JSON.stringify({
135
+ name: pageName,
136
+ description: description ?? '',
137
+ }),
138
+ });
139
+ return response.json();
140
+ }
141
+ isAuthenticated() {
142
+ return this.tokens != null;
143
+ }
144
+ async fetchWithAuth(url, options = {}) {
145
+ if (!this.tokens?.access_token) {
146
+ throw new Error('Not authenticated. Please login first.');
147
+ }
148
+ const headers = new Headers(options.headers);
149
+ headers.set('Authorization', `Bearer ${this.tokens.access_token}`);
150
+ let response = await fetch(url, { ...options, headers });
151
+ if (response.status === 401) {
152
+ await this.refreshToken();
153
+ headers.set('Authorization', `Bearer ${this.tokens.access_token}`);
154
+ response = await fetch(url, { ...options, headers });
155
+ }
156
+ if (!response.ok) {
157
+ const errorData = await response.json().catch(() => ({}));
158
+ const message = errorData.detail || errorData.error || response.statusText;
159
+ throw new Error(message);
160
+ }
161
+ return response;
162
+ }
163
+ }
164
+ exports.IPushPullClient = IPushPullClient;
165
+ /**
166
+ * Converts per-cell data (array of rows, each cell being { value, formatted_value, style })
167
+ * into the official ipushpull page content format with deduplicated styles.
168
+ */
169
+ function buildPageContentPayload(cellData) {
170
+ const values = [];
171
+ const formattedValues = [];
172
+ const uniqueStyles = [];
173
+ const cellStyles = [];
174
+ const styleIndex = new Map();
175
+ for (const row of cellData) {
176
+ const rowValues = [];
177
+ const rowFormattedValues = [];
178
+ const rowStyleIndices = [];
179
+ for (const cell of row) {
180
+ rowValues.push(cell.value);
181
+ rowFormattedValues.push(cell.formatted_value);
182
+ const styleKey = JSON.stringify(cell.style);
183
+ let idx = styleIndex.get(styleKey);
184
+ if (idx === undefined) {
185
+ idx = uniqueStyles.length;
186
+ uniqueStyles.push(cell.style);
187
+ styleIndex.set(styleKey, idx);
188
+ }
189
+ rowStyleIndices.push(idx);
190
+ }
191
+ values.push(rowValues);
192
+ formattedValues.push(rowFormattedValues);
193
+ cellStyles.push(rowStyleIndices);
194
+ }
195
+ return {
196
+ content: {
197
+ values,
198
+ formatted_values: formattedValues,
199
+ unique_styles: uniqueStyles,
200
+ cell_styles: cellStyles,
201
+ },
202
+ };
203
+ }
@@ -0,0 +1,4 @@
1
+ export { IPushPullClient, buildPageContentPayload } from './IPushPullClient';
2
+ export { getThemeStyles } from './themes';
3
+ export type { IPushPullTheme, IPushPullThemeStyles } from './themes';
4
+ export type { IPushPullClientConfig, IPushPullTokens, IPushPullPageAccessInfo, IPushPullDomainAccessInfo, IPushPullCellStyle, IPushPullPageContentPayload, IPushPullPageContentResponse, } from './types';
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getThemeStyles = exports.buildPageContentPayload = exports.IPushPullClient = void 0;
4
+ var IPushPullClient_1 = require("./IPushPullClient");
5
+ Object.defineProperty(exports, "IPushPullClient", { enumerable: true, get: function () { return IPushPullClient_1.IPushPullClient; } });
6
+ Object.defineProperty(exports, "buildPageContentPayload", { enumerable: true, get: function () { return IPushPullClient_1.buildPageContentPayload; } });
7
+ var themes_1 = require("./themes");
8
+ Object.defineProperty(exports, "getThemeStyles", { enumerable: true, get: function () { return themes_1.getThemeStyles; } });
@@ -0,0 +1,8 @@
1
+ import { IPushPullCellStyle } from './types';
2
+ export type IPushPullTheme = 'lightTheme' | 'darkTheme';
3
+ export interface IPushPullThemeStyles {
4
+ headerStyle: IPushPullCellStyle;
5
+ rowStyle: IPushPullCellStyle;
6
+ altRowStyle: IPushPullCellStyle;
7
+ }
8
+ export declare function getThemeStyles(theme: IPushPullTheme): IPushPullThemeStyles;