@adaptabletools/adaptable-plugin-ipushpull 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.
- package/package.json +1 -3
- package/src/IPushPullApiImpl.d.ts +4 -3
- package/src/IPushPullApiImpl.js +1 -1
- package/src/IPushPullPluginOptions.d.ts +59 -0
- package/src/Module/PushPullModule.js +47 -49
- package/src/Utilities/Services/IPushPullService.d.ts +39 -0
- package/src/Utilities/Services/IPushPullService.js +202 -0
- package/src/Utilities/Services/Interface/{IPushPullService.d.ts → IIPushPullService.d.ts} +2 -2
- package/src/Utilities/Services/Interface/IIPushPullService.js +1 -0
- package/src/View/IPushPullAddPagePopup.js +19 -22
- package/src/View/IPushPullLoginPopup.js +15 -18
- package/src/View/IPushPullViewPanel.js +31 -47
- package/src/index.d.ts +6 -5
- package/src/index.js +29 -38
- package/src/ipushpull-client/IPushPullClient.d.ts +28 -0
- package/src/ipushpull-client/IPushPullClient.js +198 -0
- package/src/ipushpull-client/index.d.ts +4 -0
- package/src/ipushpull-client/index.js +2 -0
- package/src/ipushpull-client/themes.d.ts +8 -0
- package/src/ipushpull-client/themes.js +159 -0
- package/src/ipushpull-client/types.d.ts +67 -0
- package/src/ipushpull-client/types.js +1 -0
- package/src/Utilities/Services/PushPullService.d.ts +0 -26
- package/src/Utilities/Services/PushPullService.js +0 -300
- package/src/View/IPushPullPopup.d.ts +0 -2
- package/src/View/IPushPullPopup.js +0 -37
- /package/src/{Utilities/Services/Interface/IPushPullService.js → IPushPullPluginOptions.js} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adaptabletools/adaptable-plugin-ipushpull",
|
|
3
|
-
"version": "22.0.
|
|
3
|
+
"version": "22.0.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"homepage": "http://www.adaptabletools.com/",
|
|
6
6
|
"author": {
|
|
@@ -9,12 +9,10 @@
|
|
|
9
9
|
},
|
|
10
10
|
"typings": "src/index.d.ts",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"ipushpull-js": "^2.25.0",
|
|
13
12
|
"react": "^18.0.0 || ^19.0.0",
|
|
14
13
|
"react-redux": "^9.2.0",
|
|
15
14
|
"redux": "^5.0.1",
|
|
16
15
|
"styled-components": "^4.4.1",
|
|
17
|
-
"tinycolor2": "^1.4.2",
|
|
18
16
|
"tslib": "^2.8.1"
|
|
19
17
|
},
|
|
20
18
|
"type": "module",
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { ApiBase } from '@adaptabletools/adaptable/src/Api/Implementation/ApiBase';
|
|
2
2
|
import { IPushPullDomain, IPushPullReport, IPushPullSchedule } from '@adaptabletools/adaptable/src/AdaptableState/IPushPullState';
|
|
3
3
|
import { IPushPullApi } from '@adaptabletools/adaptable/src/Api/IPushPullApi';
|
|
4
|
-
import { IPushPullPluginOptions } from '
|
|
4
|
+
import { IPushPullPluginOptions } from './IPushPullPluginOptions';
|
|
5
5
|
import { IAdaptable } from '@adaptabletools/adaptable/src/AdaptableInterfaces/IAdaptable';
|
|
6
|
+
import { IPushPullClient } from './ipushpull-client';
|
|
6
7
|
export declare class IPushPullApiImpl extends ApiBase implements IPushPullApi {
|
|
7
8
|
private ippInstance;
|
|
8
9
|
private ippService;
|
|
@@ -14,8 +15,8 @@ export declare class IPushPullApiImpl extends ApiBase implements IPushPullApi {
|
|
|
14
15
|
getIPushPullPassword(): string | undefined;
|
|
15
16
|
getAutoLogin(): boolean;
|
|
16
17
|
getCurrentLiveIPushPullReport(): IPushPullReport | undefined;
|
|
17
|
-
setIPushPullInstance(ippInstance:
|
|
18
|
-
getIPushPullInstance():
|
|
18
|
+
setIPushPullInstance(ippInstance: IPushPullClient): void;
|
|
19
|
+
getIPushPullInstance(): IPushPullClient | null;
|
|
19
20
|
sendSnapshot(iPushPullReport: IPushPullReport): void;
|
|
20
21
|
startLiveData(iPushPullReport: IPushPullReport): void;
|
|
21
22
|
stopLiveData(): void;
|
package/src/IPushPullApiImpl.js
CHANGED
|
@@ -4,7 +4,7 @@ import * as IPushPullRedux from './Redux/ActionReducers/IPushPullRedux';
|
|
|
4
4
|
import ArrayExtensions from '@adaptabletools/adaptable/src/Utilities/Extensions/ArrayExtensions';
|
|
5
5
|
import Helper from '@adaptabletools/adaptable/src/Utilities/Helpers/Helper';
|
|
6
6
|
export class IPushPullApiImpl extends ApiBase {
|
|
7
|
-
ippInstance;
|
|
7
|
+
ippInstance = null;
|
|
8
8
|
ippService = null;
|
|
9
9
|
options;
|
|
10
10
|
constructor(_adaptable, options) {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connection config for the ipushpull REST API.
|
|
3
|
+
*
|
|
4
|
+
* Only `api_key` and `api_secret` are required -- `api_url` defaults to the
|
|
5
|
+
* ipushpull test environment (`https://test.ipushpull.com/api/1.0`).
|
|
6
|
+
*/
|
|
7
|
+
export interface IPushPullConfig {
|
|
8
|
+
/**
|
|
9
|
+
* Base URL for the ipushpull REST API
|
|
10
|
+
*
|
|
11
|
+
* @defaultValue 'https://test.ipushpull.com/api/1.0'
|
|
12
|
+
*/
|
|
13
|
+
api_url?: string;
|
|
14
|
+
/** OAuth Client ID */
|
|
15
|
+
api_key: string;
|
|
16
|
+
/** OAuth Client Secret */
|
|
17
|
+
api_secret: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Options available in ipushpull plugin; allows users to collaborate and share data in powerful ways
|
|
21
|
+
*/
|
|
22
|
+
export interface IPushPullPluginOptions {
|
|
23
|
+
/**
|
|
24
|
+
* The config required to run ipushpull; use your ipushpull credentials
|
|
25
|
+
*/
|
|
26
|
+
ippConfig?: IPushPullConfig;
|
|
27
|
+
/**
|
|
28
|
+
* User's ipushpull user name (usually email address); if supplied, pre-populates the login screen's username textbox
|
|
29
|
+
*/
|
|
30
|
+
username?: string;
|
|
31
|
+
/**
|
|
32
|
+
* The user's ipushpull password; if supplied, pre-populates the login screen's password textbox
|
|
33
|
+
*/
|
|
34
|
+
password?: string;
|
|
35
|
+
/**
|
|
36
|
+
* How many miliseconds AdapTable should throttle when sending data updates to ipushpull
|
|
37
|
+
*
|
|
38
|
+
* @defaultValue 2000
|
|
39
|
+
*/
|
|
40
|
+
throttleTime?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Whether AdapTable should try log in to ipushpull automatically at start-up
|
|
43
|
+
*
|
|
44
|
+
* @defaultValue false
|
|
45
|
+
*/
|
|
46
|
+
autoLogin?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Whether AdapTable will include System Reports (e.g. 'All Data', 'Selected Cells' etc) in the ipushpull toolbar dropdown
|
|
49
|
+
*
|
|
50
|
+
* @defaultValue true
|
|
51
|
+
*/
|
|
52
|
+
includeSystemReports?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* The color theme to use when styling data pushed to ipushpull pages
|
|
55
|
+
*
|
|
56
|
+
* @defaultValue derived from Adaptable's current theme (lightTheme or darkTheme)
|
|
57
|
+
*/
|
|
58
|
+
cellStyles?: 'lightTheme' | 'darkTheme';
|
|
59
|
+
}
|
|
@@ -16,60 +16,58 @@ export class PushPullModule extends AdaptableModuleBase {
|
|
|
16
16
|
setTimeout(() => {
|
|
17
17
|
this.throttledRecomputeAndSendLiveDataEvent = throttle(() => this.sendNewLiveData(), this.getThrottleTimeFromState());
|
|
18
18
|
}, 1000);
|
|
19
|
-
if
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
exportApi.internalApi.isDataChangeInReport(cellDataChangedInfo, this.getCurrentReport())) {
|
|
32
|
-
this.throttledRecomputeAndSendLiveDataEvent();
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
// if the grid has refreshed then update all live reports
|
|
37
|
-
this.adaptable._on('GridRefreshed', () => {
|
|
38
|
-
if (this.getIPPApi().isIPushPullLiveDataRunning()) {
|
|
19
|
+
// if a piece of data has updated then update any live reports except cell or row selected where the data change is relevant
|
|
20
|
+
// currently we DONT send deltas - we simply send everything to ipushpull every time a relevant change happens
|
|
21
|
+
this.api.internalApi
|
|
22
|
+
.getDataService()
|
|
23
|
+
.on('CellDataChanged', (cellDataChangedInfo) => {
|
|
24
|
+
const api = this.getIPPApi();
|
|
25
|
+
const exportApi = this.api.exportApi;
|
|
26
|
+
if (api.isIPushPullLiveDataRunning()) {
|
|
27
|
+
let currentLiveIPushPullReport = api.getCurrentLiveIPushPullReport();
|
|
28
|
+
if (currentLiveIPushPullReport &&
|
|
29
|
+
currentLiveIPushPullReport.ReportName !== SELECTED_DATA_REPORT &&
|
|
30
|
+
exportApi.internalApi.isDataChangeInReport(cellDataChangedInfo, this.getCurrentReport())) {
|
|
39
31
|
this.throttledRecomputeAndSendLiveDataEvent();
|
|
40
32
|
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
// if the grid has refreshed then update all live reports
|
|
36
|
+
this.adaptable._on('GridRefreshed', () => {
|
|
37
|
+
if (this.getIPPApi().isIPushPullLiveDataRunning()) {
|
|
38
|
+
this.throttledRecomputeAndSendLiveDataEvent();
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
// if the grid filters have changed then update any live reports except cell or row selected
|
|
42
|
+
this.adaptable._on('AdapTableFiltersApplied', () => {
|
|
43
|
+
// Rerun all reports except selected cells / rows when filter changes
|
|
44
|
+
if (this.getIPPApi().isIPushPullLiveDataRunning()) {
|
|
45
|
+
let currentLiveIPushPullReport = this.getIPPApi().getCurrentLiveIPushPullReport();
|
|
46
|
+
if (currentLiveIPushPullReport &&
|
|
47
|
+
currentLiveIPushPullReport.ReportName !== SELECTED_DATA_REPORT) {
|
|
48
|
+
this.throttledRecomputeAndSendLiveDataEvent();
|
|
51
49
|
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
// if grid selection has changed and the ipushpull Live report is 'Selected Cells' or 'Selected Rows' then send updated data
|
|
53
|
+
this.api.eventApi.on('CellSelectionChanged', () => {
|
|
54
|
+
if (this.getIPPApi().isIPushPullLiveDataRunning()) {
|
|
55
|
+
let currentLiveIPushPullReport = this.getIPPApi().getCurrentLiveIPushPullReport();
|
|
56
|
+
if (currentLiveIPushPullReport &&
|
|
57
|
+
currentLiveIPushPullReport.ReportName === SELECTED_DATA_REPORT) {
|
|
58
|
+
this.throttledRecomputeAndSendLiveDataEvent();
|
|
61
59
|
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
this.api.eventApi.on('RowSelectionChanged', () => {
|
|
63
|
+
if (this.getIPPApi().isIPushPullLiveDataRunning()) {
|
|
64
|
+
let currentLiveIPushPullReport = this.getIPPApi().getCurrentLiveIPushPullReport();
|
|
65
|
+
if (currentLiveIPushPullReport &&
|
|
66
|
+
currentLiveIPushPullReport.ReportName === SELECTED_DATA_REPORT) {
|
|
67
|
+
this.throttledRecomputeAndSendLiveDataEvent();
|
|
70
68
|
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
73
71
|
});
|
|
74
72
|
}
|
|
75
73
|
getViewAccessLevel() {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { IAdaptable } from '@adaptabletools/adaptable/src/AdaptableInterfaces/IAdaptable';
|
|
2
|
+
import { IIPushPullService } from './Interface/IIPushPullService';
|
|
3
|
+
import { IPushPullDomain } from '@adaptabletools/adaptable/src/AdaptableState/InternalState';
|
|
4
|
+
import { IPushPullPluginOptions } from '../../IPushPullPluginOptions';
|
|
5
|
+
export declare enum ServiceStatus {
|
|
6
|
+
Unknown = "Unknown",
|
|
7
|
+
Disconnected = "Disconnected",
|
|
8
|
+
Connected = "Connected",
|
|
9
|
+
Error = "Error"
|
|
10
|
+
}
|
|
11
|
+
export declare class IPushPullService implements IIPushPullService {
|
|
12
|
+
adaptable: IAdaptable;
|
|
13
|
+
private client;
|
|
14
|
+
private status;
|
|
15
|
+
private cellStylesOption;
|
|
16
|
+
private pages;
|
|
17
|
+
private pageNameToId;
|
|
18
|
+
private folderNameToId;
|
|
19
|
+
constructor(adaptable: IAdaptable, cellStyles?: IPushPullPluginOptions['cellStyles']);
|
|
20
|
+
getIPushPullStatus(): ServiceStatus;
|
|
21
|
+
private getIPPApi;
|
|
22
|
+
/**
|
|
23
|
+
* Derives the IPushPull theme from Adaptable's current theme at call-time,
|
|
24
|
+
* respecting the 'os' theme by checking `prefers-color-scheme`.
|
|
25
|
+
*/
|
|
26
|
+
private deriveDefaultTheme;
|
|
27
|
+
/**
|
|
28
|
+
* Returns the resolved IPushPull theme, honouring the `cellStyles` option.
|
|
29
|
+
* If `cellStyles` is a string, it's used directly.
|
|
30
|
+
* If not set, the theme is derived from Adaptable's current theme.
|
|
31
|
+
*/
|
|
32
|
+
private getResolvedTheme;
|
|
33
|
+
login(login: string, password: string): Promise<any>;
|
|
34
|
+
getDomainPages(): Promise<IPushPullDomain[]>;
|
|
35
|
+
loadPage(folderIPP: string, pageIPP: string): Promise<void>;
|
|
36
|
+
unloadPage(page: string): void;
|
|
37
|
+
addNewPage(folderId: number, page: string): Promise<any>;
|
|
38
|
+
pushData(page: string, data: any[]): Promise<void>;
|
|
39
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import StringExtensions from '@adaptabletools/adaptable/src/Utilities/Extensions/StringExtensions';
|
|
2
|
+
import { buildPageContentPayload, getThemeStyles, } from '../../ipushpull-client';
|
|
3
|
+
export var ServiceStatus;
|
|
4
|
+
(function (ServiceStatus) {
|
|
5
|
+
ServiceStatus["Unknown"] = "Unknown";
|
|
6
|
+
ServiceStatus["Disconnected"] = "Disconnected";
|
|
7
|
+
ServiceStatus["Connected"] = "Connected";
|
|
8
|
+
ServiceStatus["Error"] = "Error";
|
|
9
|
+
})(ServiceStatus || (ServiceStatus = {}));
|
|
10
|
+
export class IPushPullService {
|
|
11
|
+
adaptable;
|
|
12
|
+
client = null;
|
|
13
|
+
status = ServiceStatus.Unknown;
|
|
14
|
+
cellStylesOption;
|
|
15
|
+
pages = new Map();
|
|
16
|
+
pageNameToId = new Map();
|
|
17
|
+
folderNameToId = new Map();
|
|
18
|
+
constructor(adaptable, cellStyles) {
|
|
19
|
+
this.adaptable = adaptable;
|
|
20
|
+
this.adaptable = adaptable;
|
|
21
|
+
this.cellStylesOption = cellStyles;
|
|
22
|
+
this.adaptable.api.eventApi.on('AdaptableReady', async () => {
|
|
23
|
+
this.getIPPApi().clearIPushPullInternalState();
|
|
24
|
+
this.getIPPApi().setIPushPullAvailableOff();
|
|
25
|
+
if (!this.client) {
|
|
26
|
+
let instance = this.getIPPApi().getIPushPullInstance();
|
|
27
|
+
if (instance) {
|
|
28
|
+
this.client = instance;
|
|
29
|
+
this.getIPPApi().setIPushPullAvailableOn();
|
|
30
|
+
let autoLogin = this.getIPPApi().getAutoLogin();
|
|
31
|
+
if (autoLogin) {
|
|
32
|
+
let userName = this.getIPPApi().getIPushPullUsername();
|
|
33
|
+
let password = this.getIPPApi().getIPushPullPassword();
|
|
34
|
+
if (StringExtensions.IsNotNullOrEmpty(userName) &&
|
|
35
|
+
StringExtensions.IsNotNullOrEmpty(password)) {
|
|
36
|
+
try {
|
|
37
|
+
this.getIPPApi().loginToIPushPull(userName, password);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
this.getIPPApi().setIPushPullRunningOff();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
getIPushPullStatus() {
|
|
49
|
+
if (!this.client) {
|
|
50
|
+
return ServiceStatus.Error;
|
|
51
|
+
}
|
|
52
|
+
return this.status;
|
|
53
|
+
}
|
|
54
|
+
getIPPApi() {
|
|
55
|
+
return this.adaptable.api.pluginsApi.getipushpullPluginApi();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Derives the IPushPull theme from Adaptable's current theme at call-time,
|
|
59
|
+
* respecting the 'os' theme by checking `prefers-color-scheme`.
|
|
60
|
+
*/
|
|
61
|
+
deriveDefaultTheme() {
|
|
62
|
+
const themeName = this.adaptable.api.themeApi.getCurrentTheme();
|
|
63
|
+
if (themeName === 'os') {
|
|
64
|
+
const preferred = this.adaptable.api.themeApi.internalApi.getDOMPreferredColorScheme();
|
|
65
|
+
return preferred === 'dark' ? 'darkTheme' : 'lightTheme';
|
|
66
|
+
}
|
|
67
|
+
const themeObj = this.adaptable.api.themeApi.getCurrentThemeObject();
|
|
68
|
+
if (themeObj?.Variant === 'dark') {
|
|
69
|
+
return 'darkTheme';
|
|
70
|
+
}
|
|
71
|
+
if (themeName === 'dark') {
|
|
72
|
+
return 'darkTheme';
|
|
73
|
+
}
|
|
74
|
+
return 'lightTheme';
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Returns the resolved IPushPull theme, honouring the `cellStyles` option.
|
|
78
|
+
* If `cellStyles` is a string, it's used directly.
|
|
79
|
+
* If not set, the theme is derived from Adaptable's current theme.
|
|
80
|
+
*/
|
|
81
|
+
getResolvedTheme() {
|
|
82
|
+
const defaultCellStyles = this.deriveDefaultTheme();
|
|
83
|
+
if (!this.cellStylesOption) {
|
|
84
|
+
return defaultCellStyles;
|
|
85
|
+
}
|
|
86
|
+
return this.cellStylesOption;
|
|
87
|
+
}
|
|
88
|
+
async login(login, password) {
|
|
89
|
+
if (!this.client) {
|
|
90
|
+
return Promise.reject('No ipushpull instance found!');
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
const result = await this.client.login(login, password);
|
|
94
|
+
this.status = ServiceStatus.Connected;
|
|
95
|
+
this.adaptable.logger.success('Logged in to ipushpull.');
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
this.status = ServiceStatus.Error;
|
|
100
|
+
const message = err.data ? err.data.error_description || err.message : err.message;
|
|
101
|
+
this.getIPPApi().setIPushPullLoginErrorMessage(message);
|
|
102
|
+
throw message;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async getDomainPages() {
|
|
106
|
+
if (!this.client) {
|
|
107
|
+
return Promise.reject('No ipushpull instance found.');
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
const domains = await this.client.getDomainsAndPages();
|
|
111
|
+
this.adaptable.logger.success('Retrieved ipushpull folder and page info.');
|
|
112
|
+
this.folderNameToId.clear();
|
|
113
|
+
this.pageNameToId.clear();
|
|
114
|
+
const result = domains.map((domain) => {
|
|
115
|
+
this.folderNameToId.set(domain.name, domain.id);
|
|
116
|
+
const writablePages = domain.pages
|
|
117
|
+
.filter((page) => page.special_page_type == 0 && page.write_access)
|
|
118
|
+
.map((page) => {
|
|
119
|
+
this.pageNameToId.set(`${domain.name}/${page.name}`, page.id);
|
|
120
|
+
return page.name;
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
Name: domain.name,
|
|
124
|
+
FolderId: domain.id,
|
|
125
|
+
Pages: writablePages,
|
|
126
|
+
};
|
|
127
|
+
});
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
this.adaptable.logger.error('Failed to retrieve folders and pages from ipushpull.', error);
|
|
132
|
+
throw error.message ?? error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async loadPage(folderIPP, pageIPP) {
|
|
136
|
+
if (!this.client) {
|
|
137
|
+
return Promise.reject('No ipushpull instance found.');
|
|
138
|
+
}
|
|
139
|
+
const folderId = this.folderNameToId.get(folderIPP);
|
|
140
|
+
const pageId = this.pageNameToId.get(`${folderIPP}/${pageIPP}`);
|
|
141
|
+
if (folderId == null || pageId == null) {
|
|
142
|
+
throw new Error(`Could not resolve IDs for folder "${folderIPP}" / page "${pageIPP}".`);
|
|
143
|
+
}
|
|
144
|
+
await this.client.getPageContent(folderId, pageId);
|
|
145
|
+
this.pages.set(pageIPP, { folderId, pageId });
|
|
146
|
+
this.adaptable.logger.info(`Page ready: "${pageIPP}".`);
|
|
147
|
+
}
|
|
148
|
+
unloadPage(page) {
|
|
149
|
+
if (this.pages.has(page)) {
|
|
150
|
+
this.pages.delete(page);
|
|
151
|
+
this.adaptable.logger.info(`Page unloaded: "${page}".`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
async addNewPage(folderId, page) {
|
|
155
|
+
if (!this.client) {
|
|
156
|
+
return Promise.reject('No ipushpull instance found.');
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
await this.client.createPage(folderId, page);
|
|
160
|
+
let message = `Page "${page}" created successfully.`;
|
|
161
|
+
this.adaptable.api.alertApi.showAlertSuccess('ipushpull', message);
|
|
162
|
+
this.adaptable.api.internalApi.hidePopupScreen();
|
|
163
|
+
return this.getIPPApi().retrieveIPushPullDomainsFromIPushPull();
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
this.adaptable.logger.error(`Failed to create page "${page}": ${err}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async pushData(page, data) {
|
|
170
|
+
const pageRef = this.pages.get(page);
|
|
171
|
+
if (!pageRef || !this.client) {
|
|
172
|
+
throw new Error(`Page "${page}" is not loaded or client is not available.`);
|
|
173
|
+
}
|
|
174
|
+
const themeStyles = getThemeStyles(this.getResolvedTheme());
|
|
175
|
+
const cellData = data.map((row, rowIndex) => row.map((cell) => {
|
|
176
|
+
let style;
|
|
177
|
+
if (rowIndex === 0) {
|
|
178
|
+
style = themeStyles.headerStyle;
|
|
179
|
+
}
|
|
180
|
+
else if (rowIndex % 2 === 1) {
|
|
181
|
+
style = themeStyles.rowStyle;
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
style = themeStyles.altRowStyle;
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
value: cell,
|
|
188
|
+
formatted_value: cell,
|
|
189
|
+
style,
|
|
190
|
+
};
|
|
191
|
+
}));
|
|
192
|
+
const payload = buildPageContentPayload(cellData);
|
|
193
|
+
try {
|
|
194
|
+
await this.client.updatePageContent(pageRef.folderId, pageRef.pageId, payload);
|
|
195
|
+
this.adaptable.logger.success(`Data pushed for ipushpull page "${page}".`);
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
this.adaptable.logger.error(`Failed to push data for ipushpull page "${page}".`);
|
|
199
|
+
throw err;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ServiceStatus } from '../
|
|
1
|
+
import { ServiceStatus } from '../IPushPullService';
|
|
2
2
|
import { IPushPullDomain } from '@adaptabletools/adaptable/src/AdaptableState/InternalState';
|
|
3
|
-
export interface
|
|
3
|
+
export interface IIPushPullService {
|
|
4
4
|
login(login: string, password: string): Promise<any>;
|
|
5
5
|
getDomainPages(): Promise<IPushPullDomain[]>;
|
|
6
6
|
loadPage(folderIPP: string, pageIPP: string): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -4,15 +4,14 @@ import * as PopupRedux from '@adaptabletools/adaptable/src/Redux/ActionsReducers
|
|
|
4
4
|
import * as IPushPullRedux from '../Redux/ActionReducers/IPushPullRedux';
|
|
5
5
|
import { StringExtensions } from '@adaptabletools/adaptable/src/Utilities/Extensions/StringExtensions';
|
|
6
6
|
import FormLayout, { FormRow } from '@adaptabletools/adaptable/src/components/FormLayout';
|
|
7
|
-
import
|
|
7
|
+
import AdaptableInput from '@adaptabletools/adaptable/src/View/Components/AdaptableInput';
|
|
8
8
|
import SimpleButton from '@adaptabletools/adaptable/src/components/SimpleButton';
|
|
9
|
-
import FlexWithFooter from '@adaptabletools/adaptable/src/components/FlexWithFooter';
|
|
10
9
|
import { PanelWithImage } from '@adaptabletools/adaptable/src/View/Components/Panels/PanelWithImage';
|
|
11
10
|
import { usePopupContext } from '@adaptabletools/adaptable/src/View/Components/Popups/AdaptablePopup/PopupContext';
|
|
12
11
|
import ErrorBox from '@adaptabletools/adaptable/src/components/ErrorBox';
|
|
13
12
|
import HelpBlock from '@adaptabletools/adaptable/src/components/HelpBlock';
|
|
14
13
|
import { Flex } from '@adaptabletools/adaptable/src/components/Flex';
|
|
15
|
-
import
|
|
14
|
+
import { Select } from '@adaptabletools/adaptable/src/components/Select';
|
|
16
15
|
import { EMPTY_STRING, EMPTY_ARRAY, } from '@adaptabletools/adaptable/src/Utilities/Constants/GeneralConstants';
|
|
17
16
|
import ArrayExtensions from '@adaptabletools/adaptable/src/Utilities/Extensions/ArrayExtensions';
|
|
18
17
|
const IPushPullAddPageComponent = (props) => {
|
|
@@ -36,11 +35,11 @@ const IPushPullAddPageComponent = (props) => {
|
|
|
36
35
|
setState({ ...state, Page: e.value });
|
|
37
36
|
};
|
|
38
37
|
const onFolderChanged = (folderName) => {
|
|
39
|
-
if (StringExtensions.IsNotNullOrEmpty(folderName)
|
|
40
|
-
let
|
|
38
|
+
if (StringExtensions.IsNotNullOrEmpty(folderName)) {
|
|
39
|
+
let availablePages = props.IPushPullDomainsPages.find((f) => f.Name == folderName)?.Pages ?? [];
|
|
41
40
|
setState({
|
|
42
41
|
Folder: folderName,
|
|
43
|
-
AvailablePages:
|
|
42
|
+
AvailablePages: availablePages,
|
|
44
43
|
Page: EMPTY_STRING,
|
|
45
44
|
ErrorMessage: EMPTY_STRING,
|
|
46
45
|
});
|
|
@@ -60,29 +59,27 @@ const IPushPullAddPageComponent = (props) => {
|
|
|
60
59
|
value: iPushPullDomain.Name,
|
|
61
60
|
};
|
|
62
61
|
});
|
|
63
|
-
return (React.createElement(PanelWithImage, { header: "Add ipushpull Page", glyphicon: "newpage", variant: "primary"
|
|
64
|
-
React.createElement(
|
|
62
|
+
return (React.createElement(PanelWithImage, { header: "Add ipushpull Page", glyphicon: "newpage", variant: "primary" },
|
|
63
|
+
React.createElement("form", { onSubmit: (e) => {
|
|
65
64
|
e.preventDefault();
|
|
66
65
|
onSubmit();
|
|
67
|
-
},
|
|
68
|
-
className: 'twa:text-4',
|
|
69
|
-
}, footer: React.createElement(React.Fragment, null,
|
|
70
|
-
React.createElement(SimpleButton, { tone: "neutral", variant: "text", tooltip: "Close", onClick: (e) => {
|
|
71
|
-
e.stopPropagation();
|
|
72
|
-
hidePopup();
|
|
73
|
-
} }, "CLOSE"),
|
|
74
|
-
React.createElement("div", { style: { flex: 1 } }),
|
|
75
|
-
React.createElement(SimpleButton, { tone: "accent", variant: "raised", type: "submit", disabled: StringExtensions.IsNullOrEmpty(state.Folder) ||
|
|
76
|
-
StringExtensions.IsNullOrEmpty(state.Page), icon: 'check' }, "Add Page")) },
|
|
66
|
+
} },
|
|
77
67
|
React.createElement(Flex, { flexDirection: "column", className: "twa:p-2 twa:m-2" },
|
|
78
68
|
React.createElement(HelpBlock, { className: "twa:mb-1" }, "Select a folder and then choose the name of the new ipushpull page it should contain."),
|
|
79
69
|
React.createElement(FormLayout, { className: "twa:m-3" },
|
|
80
|
-
React.createElement(FormRow, { label: "Folder
|
|
81
|
-
React.createElement(
|
|
70
|
+
React.createElement(FormRow, { label: "Folder" },
|
|
71
|
+
React.createElement(Select, { disabled: availableFolders.length == 0, options: availableFolders, className: "ab-Popup__IPushPull__select twa:min-w-[50%] twa:mr-2", onChange: (folder) => onFolderChanged(folder), value: state.Folder || undefined, placeholder: "Select Folder", isClearable: true })),
|
|
82
72
|
React.createElement(FormRow, { label: "Page" },
|
|
83
|
-
React.createElement(
|
|
73
|
+
React.createElement(AdaptableInput, { className: "twa:w-1/2", type: "text", placeholder: "Page Name", value: state.Page, disabled: StringExtensions.IsNullOrEmpty(state.Folder), onChange: onPageNameChange })),
|
|
84
74
|
state.ErrorMessage ? (React.createElement(FormRow, { label: "" },
|
|
85
|
-
React.createElement(ErrorBox, null, state.ErrorMessage))) : null))
|
|
75
|
+
React.createElement(ErrorBox, null, state.ErrorMessage))) : null)),
|
|
76
|
+
React.createElement(Flex, { className: "twa:p-2", justifyContent: "space-between" },
|
|
77
|
+
React.createElement(SimpleButton, { tone: "neutral", variant: "outlined", tooltip: "Close", onClick: (e) => {
|
|
78
|
+
e.stopPropagation();
|
|
79
|
+
hidePopup();
|
|
80
|
+
} }, "CLOSE"),
|
|
81
|
+
React.createElement(SimpleButton, { tone: "accent", variant: "raised", type: "submit", disabled: StringExtensions.IsNullOrEmpty(state.Folder) ||
|
|
82
|
+
StringExtensions.IsNullOrEmpty(state.Page), icon: 'check' }, "Add Page")))));
|
|
86
83
|
};
|
|
87
84
|
function mapStateToProps(state) {
|
|
88
85
|
return {
|
|
@@ -5,9 +5,8 @@ import * as PopupRedux from '@adaptabletools/adaptable/src/Redux/ActionsReducers
|
|
|
5
5
|
import * as IPushPullRedux from '../Redux/ActionReducers/IPushPullRedux';
|
|
6
6
|
import { StringExtensions } from '@adaptabletools/adaptable/src/Utilities/Extensions/StringExtensions';
|
|
7
7
|
import FormLayout, { FormRow } from '@adaptabletools/adaptable/src/components/FormLayout';
|
|
8
|
-
import
|
|
8
|
+
import AdaptableInput from '@adaptabletools/adaptable/src/View/Components/AdaptableInput';
|
|
9
9
|
import SimpleButton from '@adaptabletools/adaptable/src/components/SimpleButton';
|
|
10
|
-
import FlexWithFooter from '@adaptabletools/adaptable/src/components/FlexWithFooter';
|
|
11
10
|
import { PanelWithImage } from '@adaptabletools/adaptable/src/View/Components/Panels/PanelWithImage';
|
|
12
11
|
import { usePopupContext } from '@adaptabletools/adaptable/src/View/Components/Popups/AdaptablePopup/PopupContext';
|
|
13
12
|
import ErrorBox from '@adaptabletools/adaptable/src/components/ErrorBox';
|
|
@@ -32,28 +31,26 @@ const IPushPullLoginComponent = (props) => {
|
|
|
32
31
|
const e = event.target;
|
|
33
32
|
setState({ ...state, Password: e.value });
|
|
34
33
|
};
|
|
35
|
-
return (React.createElement(PanelWithImage, { header: "ipushpull Login Details", glyphicon: "login", variant: "primary"
|
|
36
|
-
React.createElement(
|
|
34
|
+
return (React.createElement(PanelWithImage, { header: "ipushpull Login Details", glyphicon: "login", variant: "primary" },
|
|
35
|
+
React.createElement("form", { onSubmit: (e) => {
|
|
37
36
|
e.preventDefault();
|
|
38
37
|
onSubmit();
|
|
39
|
-
},
|
|
40
|
-
className: 'twa:text-4',
|
|
41
|
-
}, footer: React.createElement(React.Fragment, null,
|
|
42
|
-
React.createElement(SimpleButton, { tone: "neutral", variant: "text", tooltip: "Close", onClick: (e) => {
|
|
43
|
-
e.stopPropagation();
|
|
44
|
-
hidePopup();
|
|
45
|
-
} }, "CLOSE"),
|
|
46
|
-
React.createElement("div", { style: { flex: 1 } }),
|
|
47
|
-
React.createElement(SimpleButton, { tone: "accent", variant: "raised", type: "submit", disabled: StringExtensions.IsNullOrEmpty(state.Password), icon: 'check' }, "Login")) },
|
|
38
|
+
} },
|
|
48
39
|
React.createElement(Flex, { flexDirection: "column", className: "twa:p-2 twa:m-2" },
|
|
49
40
|
React.createElement(HelpBlock, { className: "twa:mb-1" }, "Login to ipushpull using your login (email address) and password."),
|
|
50
41
|
React.createElement(FormLayout, { className: "twa:m-3" },
|
|
51
|
-
React.createElement(FormRow, { label: "
|
|
52
|
-
React.createElement(
|
|
53
|
-
React.createElement(FormRow, { label: "
|
|
54
|
-
React.createElement(
|
|
42
|
+
React.createElement(FormRow, { label: "User" },
|
|
43
|
+
React.createElement(AdaptableInput, { className: "twa:w-full", type: "email", placeholder: "Email address", value: state.Login, onChange: onLoginChange })),
|
|
44
|
+
React.createElement(FormRow, { label: "Password" },
|
|
45
|
+
React.createElement(AdaptableInput, { className: "twa:w-full", type: "password", placeholder: "Password", value: state.Password, onChange: onPasswordChange })),
|
|
55
46
|
props.pushpullLoginErrorMessage ? (React.createElement(FormRow, { label: "" },
|
|
56
|
-
React.createElement(ErrorBox, null, props.pushpullLoginErrorMessage))) : null))
|
|
47
|
+
React.createElement(ErrorBox, null, props.pushpullLoginErrorMessage))) : null)),
|
|
48
|
+
React.createElement(Flex, { className: "twa:p-2", justifyContent: "space-between" },
|
|
49
|
+
React.createElement(SimpleButton, { tone: "neutral", variant: "outlined", tooltip: "Close", onClick: (e) => {
|
|
50
|
+
e.stopPropagation();
|
|
51
|
+
hidePopup();
|
|
52
|
+
} }, "CLOSE"),
|
|
53
|
+
React.createElement(SimpleButton, { tone: "accent", variant: "raised", type: "submit", disabled: StringExtensions.IsNullOrEmpty(state.Password), icon: 'check' }, "Login")))));
|
|
57
54
|
};
|
|
58
55
|
function mapStateToProps(state) {
|
|
59
56
|
return {
|