Feature: Support closing dialog windows (#233)
Supports closing dialogs in development. Upgrades gas-client to 1.2.0 and uses new API here: Add scriptHostFunctions for google.script.host gas-client#36 Example button to close dialog in Bootstrap sample Updates integration tests
This commit is contained in:
@@ -9,9 +9,9 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-12, macos-13, windows-2022]
|
||||
os: [macos-13, windows-2022]
|
||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||
node-version: [18, 20]
|
||||
node-version: [20]
|
||||
timeout-minutes: 8
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -9,9 +9,9 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-12, macos-13, windows-2022]
|
||||
os: [macos-13, windows-2022]
|
||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||
node-version: [18, 20]
|
||||
node-version: [20]
|
||||
timeout-minutes: 11
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -309,8 +309,8 @@ google.script.run
|
||||
.addSheet(sheetTitle);
|
||||
|
||||
// Using gas-client we can use more familiar promises style like this:
|
||||
import Server from 'gas-client';
|
||||
const { serverFunctions } = new Server();
|
||||
import { GASClient } from 'gas-client';
|
||||
const { serverFunctions, scriptHostFunctions } = new GASClient({});
|
||||
|
||||
// We now have access to all our server functions, which return promises!
|
||||
serverFunctions
|
||||
@@ -327,6 +327,12 @@ async () => {
|
||||
handleError(err);
|
||||
}
|
||||
};
|
||||
|
||||
// Use scriptHostFunctions to control dialogs
|
||||
scriptHostFunctions.close(); // close a dialog or sidebar
|
||||
scriptHostFunctions.setWidth(400); // set dialog width to 400px
|
||||
scriptHostFunctions.setHeight(800); // set dialog height to 800px
|
||||
|
||||
```
|
||||
|
||||
In development, `gas-client` will allow you to call server-side functions from your local environment. In production, it will use Google's underlying `google.script.run` utility.
|
||||
|
||||
@@ -20,7 +20,7 @@ Two placeholders are used in this file that will need to be replaced in a build
|
||||
<base target="_top" />
|
||||
<title>Dev Server</title>
|
||||
<!-- Load gas-client as external. Exposed global variable is GASClient. -->
|
||||
<script src="https://unpkg.com/gas-client@1.1.1/dist/index.js"></script>
|
||||
<script src="https://unpkg.com/gas-client@1.2.0/dist/index.js"></script>
|
||||
<style>
|
||||
body,
|
||||
html {
|
||||
@@ -37,15 +37,21 @@ Two placeholders are used in this file that will need to be replaced in a build
|
||||
|
||||
const iframe = document.getElementById('iframe');
|
||||
iframe.src = 'https://localhost:' + PORT + '/' + FILE_NAME;
|
||||
const { serverFunctions } = new window.GASClient.GASClient({
|
||||
allowedDevelopmentDomains: (origin) =>
|
||||
/https:\/\/.*\.googleusercontent\.com$/.test(origin),
|
||||
});
|
||||
|
||||
const { serverFunctions, scriptHostFunctions } =
|
||||
new window.GASClient.GASClient({
|
||||
allowedDevelopmentDomains: (origin) =>
|
||||
/https:\/\/.*\.googleusercontent\.com$/.test(origin),
|
||||
});
|
||||
|
||||
const handleRequest = (event) => {
|
||||
const request = event.data;
|
||||
const { type, functionName, id, args } = request;
|
||||
|
||||
if (type === 'SCRIPT_HOST_FUNCTION_REQUEST') {
|
||||
scriptHostFunctions[functionName](...args);
|
||||
}
|
||||
|
||||
if (type !== 'REQUEST') return;
|
||||
|
||||
serverFunctions[functionName](...args)
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-google-apps-script",
|
||||
"version": "3.0.0",
|
||||
"version": "3.1.0",
|
||||
"type": "module",
|
||||
"description": "Starter project for using React with Google Apps Script",
|
||||
"repository": {
|
||||
@@ -41,7 +41,7 @@
|
||||
"@emotion/react": "^11.10.6",
|
||||
"@emotion/styled": "^11.10.6",
|
||||
"@mui/material": "^5.11.11",
|
||||
"gas-client": "^1.1.1",
|
||||
"gas-client": "^1.2.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^18.2.0",
|
||||
"react-bootstrap": "^2.4.0",
|
||||
|
||||
@@ -4,10 +4,14 @@ import { Button, ListGroup } from 'react-bootstrap';
|
||||
import FormInput from './FormInput';
|
||||
|
||||
// This is a wrapper for google.script.run that lets us use promises.
|
||||
import { serverFunctions } from '../../utils/serverFunctions';
|
||||
import {
|
||||
serverFunctions,
|
||||
scriptHostFunctions,
|
||||
} from '../../utils/serverFunctions';
|
||||
|
||||
const SheetEditor = () => {
|
||||
const [names, setNames] = useState([]);
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
serverFunctions.getSheetsData().then(setNames).catch(alert);
|
||||
@@ -77,6 +81,29 @@ const SheetEditor = () => {
|
||||
))}
|
||||
</TransitionGroup>
|
||||
</ListGroup>
|
||||
{names.length > 0 && (
|
||||
<div className="d-flex justify-content-end py-3">
|
||||
{!isExpanded ? (
|
||||
<Button
|
||||
variant="light"
|
||||
className="mr-2"
|
||||
onClick={() => {
|
||||
scriptHostFunctions.setHeight(1000);
|
||||
scriptHostFunctions.setWidth(1000);
|
||||
setIsExpanded(true);
|
||||
}}
|
||||
>
|
||||
Expand Dialog
|
||||
</Button>
|
||||
) : null}
|
||||
<Button
|
||||
variant="outline-dark"
|
||||
onClick={() => scriptHostFunctions.close()}
|
||||
>
|
||||
Close Dialog Window
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
></script>
|
||||
<script
|
||||
crossorigin
|
||||
src="https://unpkg.com/gas-client@1.1.1/dist/index.js"
|
||||
src="https://unpkg.com/gas-client@1.2.0/dist/index.js"
|
||||
></script>
|
||||
<script
|
||||
crossorigin
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
></script>
|
||||
<script
|
||||
crossorigin
|
||||
src="https://unpkg.com/gas-client@1.1.1/dist/index.js"
|
||||
src="https://unpkg.com/gas-client@1.2.0/dist/index.js"
|
||||
></script>
|
||||
<script
|
||||
crossorigin
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
></script>
|
||||
<script
|
||||
crossorigin
|
||||
src="https://unpkg.com/gas-client@1.1.1/dist/index.js"
|
||||
src="https://unpkg.com/gas-client@1.2.0/dist/index.js"
|
||||
></script>
|
||||
<script
|
||||
crossorigin
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
></script>
|
||||
<script
|
||||
crossorigin
|
||||
src="https://unpkg.com/gas-client@1.1.1/dist/index.js"
|
||||
src="https://unpkg.com/gas-client@1.2.0/dist/index.js"
|
||||
></script>
|
||||
<script
|
||||
crossorigin
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { GASClient } from 'gas-client';
|
||||
import * as publicServerFunctions from '../../server';
|
||||
|
||||
const { serverFunctions } = new GASClient<typeof publicServerFunctions>({
|
||||
const { serverFunctions, scriptHostFunctions } = new GASClient<
|
||||
typeof publicServerFunctions
|
||||
>({
|
||||
// this is necessary for local development but will be ignored in production
|
||||
allowedDevelopmentDomains: (origin) =>
|
||||
/https:\/\/.*\.googleusercontent\.com$/.test(origin),
|
||||
});
|
||||
|
||||
export { serverFunctions };
|
||||
export { serverFunctions, scriptHostFunctions };
|
||||
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 63 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 62 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 63 KiB |
@@ -26,7 +26,7 @@ const srcTestFile = path.join(
|
||||
'../src/client/dialog-demo-bootstrap/components/SheetEditor.jsx'
|
||||
);
|
||||
|
||||
const webpackDevServerReady = async (process) => {
|
||||
const viteDevServerReady = async (process) => {
|
||||
console.log('Waiting for vite to serve...');
|
||||
return new Promise((resolve) => {
|
||||
process.stdout.on('data', (data) => {
|
||||
@@ -40,7 +40,7 @@ const webpackDevServerReady = async (process) => {
|
||||
describe(`Local setup ${isExtended ? '*extended*' : ''}`, () => {
|
||||
let page;
|
||||
let process;
|
||||
const containerSelector = isExtended ? '.script-app-dialog' : 'body';
|
||||
const containerSelector = isExtended ? 'div[role="dialog"]' : 'body';
|
||||
|
||||
beforeAll(async () => {
|
||||
process = exec('yarn dev');
|
||||
@@ -52,7 +52,7 @@ describe(`Local setup ${isExtended ? '*extended*' : ''}`, () => {
|
||||
deviceScaleFactor: 1,
|
||||
});
|
||||
|
||||
await webpackDevServerReady(process);
|
||||
await viteDevServerReady(process);
|
||||
|
||||
if (isExtended) {
|
||||
await openAddon(page);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export const openAddon = async (page) => {
|
||||
await page.goto(process.env.SHEET_URL);
|
||||
|
||||
await page.waitForTimeout(5000); // pause for 3 seconds
|
||||
await page.click('a:nth-child(2)'); // click on signin button
|
||||
|
||||
await page.waitForSelector('input[name="identifier"]', { visible: true });
|
||||
@@ -97,10 +98,10 @@ export const openAddon = async (page) => {
|
||||
new MouseEvent('mouseup', { bubbles: true })
|
||||
);
|
||||
});
|
||||
await page.waitForSelector('.script-app-dialog', {
|
||||
await page.waitForSelector('div[role="dialog"]', {
|
||||
visible: true,
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
await page.waitForTimeout(3000);
|
||||
await page.waitForTimeout(15000);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user