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 }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
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/
|
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||||
node-version: [18, 20]
|
node-version: [20]
|
||||||
timeout-minutes: 8
|
timeout-minutes: 8
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
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/
|
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||||
node-version: [18, 20]
|
node-version: [20]
|
||||||
timeout-minutes: 11
|
timeout-minutes: 11
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|||||||
@@ -309,8 +309,8 @@ google.script.run
|
|||||||
.addSheet(sheetTitle);
|
.addSheet(sheetTitle);
|
||||||
|
|
||||||
// Using gas-client we can use more familiar promises style like this:
|
// Using gas-client we can use more familiar promises style like this:
|
||||||
import Server from 'gas-client';
|
import { GASClient } from 'gas-client';
|
||||||
const { serverFunctions } = new Server();
|
const { serverFunctions, scriptHostFunctions } = new GASClient({});
|
||||||
|
|
||||||
// We now have access to all our server functions, which return promises!
|
// We now have access to all our server functions, which return promises!
|
||||||
serverFunctions
|
serverFunctions
|
||||||
@@ -327,6 +327,12 @@ async () => {
|
|||||||
handleError(err);
|
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.
|
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" />
|
<base target="_top" />
|
||||||
<title>Dev Server</title>
|
<title>Dev Server</title>
|
||||||
<!-- Load gas-client as external. Exposed global variable is GASClient. -->
|
<!-- 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>
|
<style>
|
||||||
body,
|
body,
|
||||||
html {
|
html {
|
||||||
@@ -37,7 +37,9 @@ Two placeholders are used in this file that will need to be replaced in a build
|
|||||||
|
|
||||||
const iframe = document.getElementById('iframe');
|
const iframe = document.getElementById('iframe');
|
||||||
iframe.src = 'https://localhost:' + PORT + '/' + FILE_NAME;
|
iframe.src = 'https://localhost:' + PORT + '/' + FILE_NAME;
|
||||||
const { serverFunctions } = new window.GASClient.GASClient({
|
|
||||||
|
const { serverFunctions, scriptHostFunctions } =
|
||||||
|
new window.GASClient.GASClient({
|
||||||
allowedDevelopmentDomains: (origin) =>
|
allowedDevelopmentDomains: (origin) =>
|
||||||
/https:\/\/.*\.googleusercontent\.com$/.test(origin),
|
/https:\/\/.*\.googleusercontent\.com$/.test(origin),
|
||||||
});
|
});
|
||||||
@@ -46,6 +48,10 @@ Two placeholders are used in this file that will need to be replaced in a build
|
|||||||
const request = event.data;
|
const request = event.data;
|
||||||
const { type, functionName, id, args } = request;
|
const { type, functionName, id, args } = request;
|
||||||
|
|
||||||
|
if (type === 'SCRIPT_HOST_FUNCTION_REQUEST') {
|
||||||
|
scriptHostFunctions[functionName](...args);
|
||||||
|
}
|
||||||
|
|
||||||
if (type !== 'REQUEST') return;
|
if (type !== 'REQUEST') return;
|
||||||
|
|
||||||
serverFunctions[functionName](...args)
|
serverFunctions[functionName](...args)
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-google-apps-script",
|
"name": "react-google-apps-script",
|
||||||
"version": "3.0.0",
|
"version": "3.1.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Starter project for using React with Google Apps Script",
|
"description": "Starter project for using React with Google Apps Script",
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
"@emotion/react": "^11.10.6",
|
"@emotion/react": "^11.10.6",
|
||||||
"@emotion/styled": "^11.10.6",
|
"@emotion/styled": "^11.10.6",
|
||||||
"@mui/material": "^5.11.11",
|
"@mui/material": "^5.11.11",
|
||||||
"gas-client": "^1.1.1",
|
"gas-client": "^1.2.0",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-bootstrap": "^2.4.0",
|
"react-bootstrap": "^2.4.0",
|
||||||
|
|||||||
@@ -4,10 +4,14 @@ import { Button, ListGroup } from 'react-bootstrap';
|
|||||||
import FormInput from './FormInput';
|
import FormInput from './FormInput';
|
||||||
|
|
||||||
// This is a wrapper for google.script.run that lets us use promises.
|
// 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 SheetEditor = () => {
|
||||||
const [names, setNames] = useState([]);
|
const [names, setNames] = useState([]);
|
||||||
|
const [isExpanded, setIsExpanded] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
serverFunctions.getSheetsData().then(setNames).catch(alert);
|
serverFunctions.getSheetsData().then(setNames).catch(alert);
|
||||||
@@ -77,6 +81,29 @@ const SheetEditor = () => {
|
|||||||
))}
|
))}
|
||||||
</TransitionGroup>
|
</TransitionGroup>
|
||||||
</ListGroup>
|
</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>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
></script>
|
></script>
|
||||||
<script
|
<script
|
||||||
crossorigin
|
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>
|
||||||
<script
|
<script
|
||||||
crossorigin
|
crossorigin
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
></script>
|
></script>
|
||||||
<script
|
<script
|
||||||
crossorigin
|
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>
|
||||||
<script
|
<script
|
||||||
crossorigin
|
crossorigin
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
></script>
|
></script>
|
||||||
<script
|
<script
|
||||||
crossorigin
|
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>
|
||||||
<script
|
<script
|
||||||
crossorigin
|
crossorigin
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
></script>
|
></script>
|
||||||
<script
|
<script
|
||||||
crossorigin
|
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>
|
||||||
<script
|
<script
|
||||||
crossorigin
|
crossorigin
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { GASClient } from 'gas-client';
|
import { GASClient } from 'gas-client';
|
||||||
import * as publicServerFunctions from '../../server';
|
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
|
// this is necessary for local development but will be ignored in production
|
||||||
allowedDevelopmentDomains: (origin) =>
|
allowedDevelopmentDomains: (origin) =>
|
||||||
/https:\/\/.*\.googleusercontent\.com$/.test(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'
|
'../src/client/dialog-demo-bootstrap/components/SheetEditor.jsx'
|
||||||
);
|
);
|
||||||
|
|
||||||
const webpackDevServerReady = async (process) => {
|
const viteDevServerReady = async (process) => {
|
||||||
console.log('Waiting for vite to serve...');
|
console.log('Waiting for vite to serve...');
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
process.stdout.on('data', (data) => {
|
process.stdout.on('data', (data) => {
|
||||||
@@ -40,7 +40,7 @@ const webpackDevServerReady = async (process) => {
|
|||||||
describe(`Local setup ${isExtended ? '*extended*' : ''}`, () => {
|
describe(`Local setup ${isExtended ? '*extended*' : ''}`, () => {
|
||||||
let page;
|
let page;
|
||||||
let process;
|
let process;
|
||||||
const containerSelector = isExtended ? '.script-app-dialog' : 'body';
|
const containerSelector = isExtended ? 'div[role="dialog"]' : 'body';
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
process = exec('yarn dev');
|
process = exec('yarn dev');
|
||||||
@@ -52,7 +52,7 @@ describe(`Local setup ${isExtended ? '*extended*' : ''}`, () => {
|
|||||||
deviceScaleFactor: 1,
|
deviceScaleFactor: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
await webpackDevServerReady(process);
|
await viteDevServerReady(process);
|
||||||
|
|
||||||
if (isExtended) {
|
if (isExtended) {
|
||||||
await openAddon(page);
|
await openAddon(page);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
export const openAddon = async (page) => {
|
export const openAddon = async (page) => {
|
||||||
await page.goto(process.env.SHEET_URL);
|
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.click('a:nth-child(2)'); // click on signin button
|
||||||
|
|
||||||
await page.waitForSelector('input[name="identifier"]', { visible: true });
|
await page.waitForSelector('input[name="identifier"]', { visible: true });
|
||||||
@@ -97,10 +98,10 @@ export const openAddon = async (page) => {
|
|||||||
new MouseEvent('mouseup', { bubbles: true })
|
new MouseEvent('mouseup', { bubbles: true })
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
await page.waitForSelector('.script-app-dialog', {
|
await page.waitForSelector('div[role="dialog"]', {
|
||||||
visible: true,
|
visible: true,
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
});
|
});
|
||||||
|
|
||||||
await page.waitForTimeout(3000);
|
await page.waitForTimeout(15000);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user