Skip to content

Commit 7d9962d

Browse files
prateeknainPrateek Chaudhary
andauthored
Tenant properties (#91)
* initial checkin * fetching all tenant properties * new and edit forms * removed unwanted code * Adding a new tenant property * delete tenant property --------- Co-authored-by: Prateek Chaudhary <[email protected]>
1 parent e1db32a commit 7d9962d

File tree

15 files changed

+1456
-109
lines changed

15 files changed

+1456
-109
lines changed

src/App.tsx

Lines changed: 47 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
1-
import { useEffect } from "react";
2-
import PnPjsConsole from "./pages/pnpjsconsole";
1+
import { useEffect } from 'react';
2+
import PnPjsConsole from './pages/pnpjsconsole';
33

4-
import { IonApp, IonRouterOutlet, setupIonicReact } from "@ionic/react";
4+
import { IonApp, IonRouterOutlet, setupIonicReact } from '@ionic/react';
55

6-
import "./App.css";
7-
import { FabricNav } from "./components/navigation";
8-
import HomePage from "./pages/home/homePage";
9-
import ScriptLinks from "./pages/scriptlinks";
10-
import { Route, Routes, HashRouter } from "react-router-dom";
6+
import './App.css';
7+
import { FabricNav } from './components/navigation';
8+
import HomePage from './pages/home/homePage';
9+
import ScriptLinks from './pages/scriptlinks';
10+
import { Route, Routes, HashRouter } from 'react-router-dom';
1111

1212
/* Core CSS required for Ionic components to work properly */
13-
import "@ionic/react/css/core.css";
13+
import '@ionic/react/css/core.css';
1414

1515
/* Basic CSS for apps built with Ionic */
16-
import "@ionic/react/css/normalize.css";
17-
import "@ionic/react/css/structure.css";
18-
import "@ionic/react/css/typography.css";
16+
import '@ionic/react/css/normalize.css';
17+
import '@ionic/react/css/structure.css';
18+
import '@ionic/react/css/typography.css';
1919

2020
/* Optional CSS utils that can be commented out */
21-
import "@ionic/react/css/padding.css";
22-
import "@ionic/react/css/float-elements.css";
23-
import "@ionic/react/css/text-alignment.css";
24-
import "@ionic/react/css/text-transformation.css";
25-
import "@ionic/react/css/flex-utils.css";
26-
import "@ionic/react/css/display.css";
21+
import '@ionic/react/css/padding.css';
22+
import '@ionic/react/css/float-elements.css';
23+
import '@ionic/react/css/text-alignment.css';
24+
import '@ionic/react/css/text-transformation.css';
25+
import '@ionic/react/css/flex-utils.css';
26+
import '@ionic/react/css/display.css';
2727

2828
/**
2929
* Ionic Dark Mode
@@ -37,36 +37,33 @@ import "@ionic/react/css/display.css";
3737
//import "@ionic/react/css/palettes/dark.system.css";
3838

3939
/* Theme variables */
40-
import "./theme/variables.css";
41-
42-
import { Fabric } from "@fluentui/react";
43-
import { Customizer } from "@fluentui/react/lib/Utilities";
44-
45-
import {
46-
DarkCustomizations,
47-
DefaultCustomizations,
48-
} from "@fluentui/theme-samples";
49-
import { useDispatch, useSelector } from "react-redux";
50-
import MessageBar from "./components/messageBar";
51-
import GraphSDKConsole from "./pages/graphsdkconsole";
52-
import ListProperties from "./pages/listproperties";
53-
import MGTConsole from "./pages/mgtconsole";
54-
import SPShooter from "./pages/spshooter";
55-
import Webhooks from "./pages/webhooks";
56-
import WebProperties from "./pages/webproperties";
57-
import { IRootState } from "./store";
58-
import { setDarkMode, setTheme } from "./store/home/actions";
59-
import Search from "./pages/search";
60-
import { menuController } from "@ionic/core";
61-
import "./index.css";
62-
import FileExplorer from "./pages/fileexplorer";
63-
import InfoPage from "./pages/Info/infoPage";
64-
import Proxy from "./pages/proxy";
65-
40+
import './theme/variables.css';
41+
42+
import { Fabric } from '@fluentui/react';
43+
import { Customizer } from '@fluentui/react/lib/Utilities';
44+
45+
import { DarkCustomizations, DefaultCustomizations } from '@fluentui/theme-samples';
46+
import { useDispatch, useSelector } from 'react-redux';
47+
import MessageBar from './components/messageBar';
48+
import GraphSDKConsole from './pages/graphsdkconsole';
49+
import ListProperties from './pages/listproperties';
50+
import MGTConsole from './pages/mgtconsole';
51+
import SPShooter from './pages/spshooter';
52+
import Webhooks from './pages/webhooks';
53+
import WebProperties from './pages/webproperties';
54+
import TenantProperties from './pages/tenantproperties';
55+
import { IRootState } from './store';
56+
import { setDarkMode, setTheme } from './store/home/actions';
57+
import Search from './pages/search';
58+
import { menuController } from '@ionic/core';
59+
import './index.css';
60+
import FileExplorer from './pages/fileexplorer';
61+
import InfoPage from './pages/Info/infoPage';
62+
import Proxy from './pages/proxy';
6663

6764
setupIonicReact();
6865

69-
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)");
66+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
7067

7168
document.body.style.minWidth = 100 + '%';
7269
document.body.style.minHeight = 100 + '%';
@@ -80,29 +77,24 @@ const App = () => {
8077

8178
useEffect(() => {
8279
const toggleDarkTheme = (shouldAdd: boolean) => {
83-
document.body.classList.toggle("dark", shouldAdd);
84-
dispatch(
85-
setTheme(shouldAdd ? DarkCustomizations : DefaultCustomizations)
86-
);
80+
document.body.classList.toggle('dark', shouldAdd);
81+
dispatch(setTheme(shouldAdd ? DarkCustomizations : DefaultCustomizations));
8782
dispatch(setDarkMode(shouldAdd));
8883
};
8984

9085
// toggleDarkTheme(prefersDark.matches)
9186
// this will set the theme according the system preferences
9287
// now we default to dark (true)
9388
toggleDarkTheme(true);
94-
prefersDark.addListener((mediaQuery) =>
95-
toggleDarkTheme(mediaQuery.matches)
96-
);
89+
prefersDark.addListener((mediaQuery) => toggleDarkTheme(mediaQuery.matches));
9790
}, [dispatch]);
9891

99-
10092
useEffect(() => {
10193
const menu = document.querySelector('ion-menu') as any;
10294
if (menu) {
10395
menu.open();
10496
}
105-
}, []);
97+
}, []);
10698

10799
return (
108100
<IonApp>
@@ -118,6 +110,7 @@ const App = () => {
118110
<Route path="/pnpjsconsole" element={<PnPjsConsole />} />
119111
<Route path="/webproperties" element={<WebProperties />} />
120112
<Route path="/listproperties" element={<ListProperties />} />
113+
<Route path="/tenantproperties" element={<TenantProperties />} />
121114
<Route path="/webhooks" element={<Webhooks />} />
122115
<Route path="/spshooter" element={<SPShooter />} />
123116
<Route path="/graphsdkconsole" element={<GraphSDKConsole />} />

src/components/navigation.tsx

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,17 @@
1-
import { FontIcon, Nav, ScrollablePane, TooltipDelay, TooltipHost, Text, Stack } from '@fluentui/react'
2-
import {
3-
IonButton,
4-
IonButtons,
5-
IonContent,
6-
IonHeader,
7-
IonMenu,
8-
IonTitle,
9-
IonToggle,
10-
IonToolbar,
11-
} from '@ionic/react'
12-
import { DarkCustomizations, DefaultCustomizations } from '@fluentui/theme-samples'
13-
import React, { useState } from 'react'
14-
import { useDispatch, useSelector } from 'react-redux'
1+
import { FontIcon, Nav, ScrollablePane, TooltipDelay, TooltipHost, Text, Stack } from '@fluentui/react';
2+
import { IonButton, IonButtons, IonContent, IonHeader, IonMenu, IonTitle, IonToggle, IonToolbar } from '@ionic/react';
3+
import { DarkCustomizations, DefaultCustomizations } from '@fluentui/theme-samples';
4+
import React, { useState } from 'react';
5+
import { useDispatch, useSelector } from 'react-redux';
156
import { useNavigate } from 'react-router-dom';
167

17-
import { IRootState } from '../store'
18-
import { setDarkMode, setLoading, setTheme } from '../store/home/actions'
8+
import { IRootState } from '../store';
9+
import { setDarkMode, setLoading, setTheme } from '../store/home/actions';
1910

2011
export const FabricNav = () => {
2112
const navigate = useNavigate();
2213

23-
24-
const dispatch = useDispatch()
14+
const dispatch = useDispatch();
2515

2616
const navLinks = [
2717
{
@@ -121,17 +111,22 @@ export const FabricNav = () => {
121111
key: 'key16',
122112
disabled: false,
123113
},
124-
]
114+
{
115+
name: 'Tenant Properties',
116+
url: '/tenantproperties',
117+
key: 'key17',
118+
},
119+
];
125120

126-
const currentLink = navLinks.find(x => x.url === document.location.pathname)
127-
const [selectedKey, setSelectedKey] = useState(currentLink?.key ?? 'key1')
128-
const { isDark } = useSelector((state: IRootState) => state.home)
121+
const currentLink = navLinks.find((x) => x.url === document.location.pathname);
122+
const [selectedKey, setSelectedKey] = useState(currentLink?.key ?? 'key1');
123+
const { isDark } = useSelector((state: IRootState) => state.home);
129124

130125
const toggleDarkTheme = () => {
131-
document.body.classList.toggle('dark', !isDark)
132-
dispatch(setTheme(!isDark ? DarkCustomizations : DefaultCustomizations))
133-
dispatch(setDarkMode(!isDark))
134-
}
126+
document.body.classList.toggle('dark', !isDark);
127+
dispatch(setTheme(!isDark ? DarkCustomizations : DefaultCustomizations));
128+
dispatch(setDarkMode(!isDark));
129+
};
135130

136131
return (
137132
<IonMenu contentId="main">
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
import { Dispatch } from 'redux';
2+
import * as rootActions from '../../../store/home/actions';
3+
import { HomeActions, MessageBarColors } from '../../../store/home/types';
4+
import * as actions from '../../../store/tenantproperties/actions';
5+
import { ITenantProperty, TenantPropertiesActions } from '../../../store/tenantproperties/types';
6+
import { spDelay } from '../../../utilities/utilities';
7+
import { createTenantProperty } from './createtenantproperty';
8+
import { deleteTenantProperties } from './deletetenantproperties';
9+
import { getTenantProperties } from './gettenantproperties';
10+
11+
export async function getAllTenantProperties(dispatch: Dispatch<TenantPropertiesActions | HomeActions>) {
12+
dispatch(rootActions.setLoading(true));
13+
14+
chrome.scripting
15+
.executeScript({
16+
target: { tabId: chrome.devtools.inspectedWindow.tabId },
17+
world: 'MAIN',
18+
args: [chrome.runtime.getURL('')],
19+
func: getTenantProperties,
20+
})
21+
.then((injectionResults) => {
22+
if (injectionResults[0].result) {
23+
const res = injectionResults[0].result as any;
24+
if (res.success === false) {
25+
dispatch(
26+
rootActions.setAppMessage({
27+
showMessage: true,
28+
message: res.errorMessage,
29+
color: MessageBarColors.danger,
30+
})
31+
);
32+
dispatch(actions.setAllTenantProperties([]));
33+
} else {
34+
/* on success */
35+
let tenantProperties: ITenantProperty[] = res;
36+
37+
const vti_indexedpropertykeys = tenantProperties.find((obj) => {
38+
return obj.key === 'vti_indexedpropertykeys';
39+
});
40+
41+
// find indexed properties
42+
if (
43+
vti_indexedpropertykeys &&
44+
vti_indexedpropertykeys.value &&
45+
vti_indexedpropertykeys.value.indexOf('|') > -1
46+
) {
47+
tenantProperties = tenantProperties.map((property) => {
48+
const bytes = [];
49+
for (let i = 0; i < property.key.length; ++i) {
50+
bytes.push(property.key.charCodeAt(i));
51+
bytes.push(0);
52+
}
53+
const b64encoded = window.btoa(String.fromCharCode.apply(null, bytes));
54+
return property;
55+
});
56+
}
57+
58+
// add tenantproperties to state
59+
dispatch(actions.setAllTenantProperties(tenantProperties));
60+
}
61+
// hide loading component
62+
dispatch(rootActions.setLoading(false));
63+
}
64+
});
65+
}
66+
67+
export async function addTenantProperty(
68+
dispatch: Dispatch<TenantPropertiesActions | HomeActions>,
69+
payload: ITenantProperty,
70+
update: boolean
71+
) {
72+
// show loading spinner
73+
dispatch(rootActions.setLoading(true));
74+
// close panel
75+
if (update) {
76+
dispatch(actions.setConfirmEditDialog(true));
77+
dispatch(actions.setEditPanel(false));
78+
} else {
79+
dispatch(actions.setNewPanel(false));
80+
}
81+
82+
chrome.scripting
83+
.executeScript({
84+
target: { tabId: chrome.devtools.inspectedWindow.tabId },
85+
world: 'MAIN',
86+
args: [payload, chrome.runtime.getURL('')],
87+
func: createTenantProperty,
88+
})
89+
.then(async (injectionResults) => {
90+
if (injectionResults[0].result) {
91+
const res = injectionResults[0].result as any;
92+
if (res.success) {
93+
/* on success */
94+
// add small delay just be sure SP can process previous requests
95+
await spDelay(500);
96+
// load all scriptlinks
97+
getAllTenantProperties(dispatch);
98+
// set success message
99+
dispatch(
100+
rootActions.setAppMessage({
101+
showMessage: true,
102+
message: !update ? 'Tenant Property added succesfully!' : 'Tenant Property updated succesfully!',
103+
color: MessageBarColors.success,
104+
})
105+
);
106+
} else {
107+
/* on error */
108+
// hide loading
109+
dispatch(rootActions.setLoading(false));
110+
// show error message
111+
dispatch(
112+
rootActions.setAppMessage({
113+
showMessage: true,
114+
message: res.errorMessage,
115+
color: MessageBarColors.danger,
116+
})
117+
);
118+
}
119+
}
120+
});
121+
}
122+
123+
export async function removeTenantProperties(
124+
dispatch: Dispatch<TenantPropertiesActions | HomeActions>,
125+
payload: ITenantProperty[]
126+
) {
127+
// hide confirm dialog
128+
dispatch(actions.setConfirmRemoveDialog(true));
129+
// show loading spinner
130+
dispatch(rootActions.setLoading(true));
131+
132+
chrome.scripting
133+
.executeScript({
134+
target: { tabId: chrome.devtools.inspectedWindow.tabId },
135+
world: 'MAIN',
136+
args: [payload, chrome.runtime.getURL('')],
137+
func: deleteTenantProperties,
138+
})
139+
.then(async (injectionResults) => {
140+
if (injectionResults[0].result) {
141+
const res = injectionResults[0].result as any;
142+
if (res.success) {
143+
/* on success */
144+
// add small delay just be sure SP can process previous requests
145+
await spDelay(500);
146+
// load all scriptlinks
147+
getAllTenantProperties(dispatch);
148+
// set success message
149+
dispatch(
150+
rootActions.setAppMessage({
151+
showMessage: true,
152+
message: 'Tenant properties removed succesfully!',
153+
color: MessageBarColors.success,
154+
})
155+
);
156+
} else {
157+
/* on error */
158+
// hide loading
159+
dispatch(rootActions.setLoading(false));
160+
// set error message
161+
dispatch(
162+
rootActions.setAppMessage({
163+
showMessage: true,
164+
message: res.errorMessage,
165+
color: MessageBarColors.danger,
166+
})
167+
);
168+
}
169+
}
170+
});
171+
}

0 commit comments

Comments
 (0)