Azure Cloud demo refresh

This commit is contained in:
SheetJS 2024-06-13 00:31:40 -04:00
parent 9c0d1bc162
commit 9d9478e6e5
7 changed files with 259 additions and 99 deletions

@ -5,44 +5,174 @@ pagination_next: demos/net/index
---
import current from '/version.js';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
This demo covers the traditional Material UI Table as well as the MUI Data Grid.
Material UI is a collection of ReactJS Components that follows the
[Google Material Design system](https://material.io/)
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
data from spreadsheets.
This demo uses Material UI and SheetJS to pull data from a spreadsheet and
display the data. We'll explore how to import data from spreadsheets and export
data to spreadsheets. The following Material UI components will be tested:
- ["Table"](#material-ui-table) is based on the core HTML TABLE element.
- ["Data Grid"](#material-ui-data-grid) is a data grid for larger datasets.
:::note pass
The [ReactJS demo](/docs/demos/frontend/react) covers basic ReactJS concepts.
It should be perused before reading this demo.
:::
## Integration Details
[The "Frameworks" section](/docs/getting-started/installation/frameworks) covers
installation in projects using Material UI.
After installing the SheetJS module in a ReactJS project, `import` statements
can load relevant parts of the library.
```js
import { read, utils, writeFileXLSX } from 'xlsx';
```
## Material UI Table
The `Table` component abstracts the `<table>` element in HTML. `table_to_book`
can process a `ref` attached to the `Table` element:
The `Table` component abstracts the `<table>` element in HTML.
```tsx
import TableContainer from '@mui/material/TableContainer';
import Table from '@mui/material/Table';
// ...
### Importing Data
Starting from a SheetJS worksheet object[^1], the `sheet_to_json` method[^2]
generates an array of row objects.
In the [ReactJS "Array of Objects" demo](/docs/demos/frontend/react), the array
of objects is rendered by manually mapping over data. For example, starting from
the following spreadsheet and data:
<table>
<thead><tr><th>Spreadsheet</th><th>State</th></tr></thead>
<tbody><tr><td>
![`pres.xlsx` data](pathname:///pres.png)
</td><td>
```js
[
{ Name: "Bill Clinton", Index: 42 },
{ Name: "GeorgeW Bush", Index: 43 },
{ Name: "Barack Obama", Index: 44 },
{ Name: "Donald Trump", Index: 45 },
{ Name: "Joseph Biden", Index: 46 }
]
```
</td></tr></tbody></table>
The HTML table elements map to MUI components:
| HTML | MUI |
|:--------|:------------|
| `TABLE` | `Table` |
| `THEAD` | `TableHead` |
| `TBODY` | `TableBody` |
| `TR` | `TableRow` |
| `TD` | `TableCell` |
The library requires a `TableContainer` container component.
The following example JSX shows a table using HTML and using MUI components:
<Tabs>
<TabItem value="ReactJS" label="ReactJS">
```jsx title="Example JSX for displaying arrays of objects"
<table>
{/* The `thead` section includes the table header row */}
<thead><tr><th>Name</th><th>Index</th></tr></thead>
{/* The `tbody` section includes the data rows */}
<tbody>
{/* generate row (TR) for each president */}
// highlight-start
{pres.map(row => (
<tr>
{/* Generate cell (TD) for name / index */}
<td>{row.Name}</td>
<td>{row.Index}</td>
</tr>
))}
// highlight-end
</tbody>
</table>
```
</TabItem>
<TabItem value="MUI" label="Material UI">
```jsx title="Example JSX for displaying arrays of objects"
<TableContainer><Table>
{/* The `TableHead` section includes the table header row */}
<TableHead><TableRow><TableCell>Name</TableCell><TableCell>Index</TableCell></TableRow></TableHead>
{/* The `TableBody` section includes the data rows */}
<TableBody>
{/* generate row (TableRow) for each president */}
// highlight-start
{pres.map((row, idx) => (
<TableRow key={idx}>
{/* Generate cell (TableCell) for name / index */}
<TableCell>{row.Name}</TableCell>
<TableCell>{row.Index}</TableCell>
</TableRow>
))}
// highlight-end
</TableBody>
</Table></TableContainer>
```
</TabItem>
</Tabs>
### Exporting Data
The SheetJS `table_to_book` method[^3] can parse data from a DOM element.
The MUI `Table` element is really a HTML TABLE element under the hood. A `ref`
attached to the `Table` element can be processed by `table_to_book`.
The following snippet uses the `writeFileXLSX` method[^4] to generate and
download a XLSX workbook:
```tsx title="Skeleton Component for exporting a Material UI Table"
// highlight-start
import { utils, writeFileXLSX } from "xlsx";
import { useRef } from "react";
// highlight-end
// ...
export default function BasicTable() {
export default function MUITableSheetJSExport() {
/* This ref will be attached to the <Table> component */
// highlight-next-line
const tbl = useRef<HTMLTableElement>(null);
const xport = () => {
/* the .current field will be a TABLE element */
const table_elt = tbl.current;
/* generate SheetJS workbook */
// highlight-next-line
const wb = utils.table_to_book(table_elt);
/* export to XLSX */
writeFileXLSX(wb, "SheetJSMaterialUI.xlsx");
};
return ( <>
<button onClick={() => {
// highlight-next-line
const wb = utils.table_to_book(tbl.current);
writeFileXLSX(wb, "SheetJSMaterialUI.xlsx");
}}>Export</button>
<TableContainer {...}>
<button onClick={xport}>Export</button>
<TableContainer>
// highlight-next-line
<Table {...} ref={tbl}>
{/* ... material ui table machinations ... */}
</Table>
<Table ref={tbl}>{/* ... */}</Table>
</TableContainer>
<>);
}
@ -52,8 +182,11 @@ export default function BasicTable() {
:::note Tested Deployments
This demo was last run on 2023 December 04 against Material UI 5.14.19 paired
with Emotion 11.11.1
This demo was tested in the following deployments:
| Material UI | Emotion | Date |
|:------------|:----------|:-----------|
| `5.15.20` | `11.11.4` | 2024-06-12 |
:::
@ -67,7 +200,7 @@ cd sheetjs-mui
2) Install dependencies:
<CodeBlock language="bash">{`\
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @mui/material@5.14.19 @emotion/react@11.11.1 @emotion/styled@11.11.0`}
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @mui/material@5.15.20 @emotion/react@11.11.4 @emotion/styled@11.11.5`}
</CodeBlock>
3) Download [`App.tsx`](pathname:///mui/table/App.tsx) and replace `src/App.tsx`.
@ -195,8 +328,11 @@ export default function App() {
:::note Tested Deployments
This demo was last run on 2023 December 04 against MUI data grid 6.18.3 paired
with Emotion 11.11.1
This demo was tested in the following deployments:
| Data Grid | Emotion | Date |
|:----------|:----------|:-----------|
| `7.6.2` | `11.11.4` | 2024-06-12 |
:::
@ -210,7 +346,7 @@ cd sheetjs-muidg
2) Install dependencies:
<CodeBlock language="bash">{`\
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @mui/x-data-grid@6.18.3 @emotion/react@11.11.1 @emotion/styled@11.11.0`}
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @mui/x-data-grid@7.6.2 @emotion/react@11.11.4 @emotion/styled@11.11.5`}
</CodeBlock>
3) Download [`App.tsx`](pathname:///mui/dg/App.tsx) and replace `src/App.tsx`.
@ -226,3 +362,8 @@ npm run dev
```
When the page loads, it will process https://docs.sheetjs.com/pres.numbers
[^1]: See ["Sheet Objects"](/docs/csf/sheet)
[^2]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
[^3]: See [`table_to_book` in "HTML" Utilities](/docs/api/utilities/html#create-new-sheet)
[^4]: See [`writeFileXLSX` in "Writing Files"](/docs/api/write-options)

@ -35,7 +35,7 @@ will be available in the future.
:::note Tested Deployments
This demo was last tested on 2023 October 06.
This demo was last tested on 2024 June 12.
:::
@ -252,6 +252,17 @@ sudo npm i -g azure-functions-core-tools@4 --unsafe-perm true
3) Install [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli)
<details>
<summary><b>Installation Notes</b> (click to show)</summary>
On macOS, `azure-cli` can be installed from Homebrew:
```bash
brew install azure-cli
```
</details>
4) Disable Azure CLI telemetry:
```bash
@ -268,6 +279,10 @@ cd SheetJSAzure
func new --template httpTrigger --language JavaScript --name SheetJSAzure
```
If prompted for a worker runtime, select `node` (Press <kbd>3</kbd>)
If prompted for a language, select `javascript` (Press <kbd>1</kbd>)
:::danger pass
When the demo was last tested, the stock TypeScript template did not work.
@ -333,19 +348,21 @@ Open in Excel or another spreadsheet editor to confirm the file is valid.
13) Sign into the [Azure Portal](https://portal.azure.com/#home)
14) Type "Function App" in the top search box and click "Function App"
14) Type "Function App" in the top search box and click "Function App":
![Function App](pathname:///azure/functionapp.png)
15) Click "+ Create"
16) Select the following options:
- "Select a hosting option": "Consumption"
- Type a memorable "Function Name" ("sheetjsazure" when last tested)
- "Do you want to deploy code or container image?": select "Code"
- "Operating System": "Windows"
- "Runtime stack": select NodeJS
- "Hosting options and plans": "Consumption (Serverless)"
- "Runtime stack": select `Node.js`
17) Click "Review + create", then click "Create" to create the function.
@ -359,7 +376,7 @@ When the resources are configured, the status will change to
18) Click "Go to Resource".
19) Take note of the URL from the table
19) Take note of the URL from the "Essentials" table.
#### Deploy to Azure
@ -388,8 +405,24 @@ Functions in sheetjsazure:
Take note of that URL.
#### Remote Test
:::danger pass
When this demo was last tested using the "Linux" operating system, the command
failed with a support error:
```
Azure Functions Core Tools does not support this deployment path. Please configure the app to deploy from a remote package using the steps here: https://aka.ms/deployfromurl
```
**This is a limitation of the Azure CLI tool with Linux functions!**
Ensure that the selected operating system is "Windows".
SheetJS libraries run in Linux-based functions.
:::
#### Remote Test
22) In a new terminal window, download https://docs.sheetjs.com/pres.numbers and
make a POST request to the production server. Replace `FUNCTION_URL` with the
@ -501,7 +534,9 @@ requests and 2000 write requests per month.
1) Sign into the [Azure Portal](https://portal.azure.com/#home)
2) Type "Storage" in the top search box and click "Storage accounts"
2) Type "Storage" in the top search box and click "Storage accounts":
![Storage Accounts](pathname:///azure/storageacct.png)
3) Click "+ Create"
@ -511,8 +546,6 @@ requests and 2000 write requests per month.
- "Redundancy": select LRS (Locally-redundant storage)
- "Hosting options and plans": "Consumption (Serverless)"
5) Click "Review", then click "Create" to create the storage.
The page will display a status message
@ -527,15 +560,17 @@ When the resources are configured, the status will change to
#### Access Keys
7) Click "Access keys" in the left sidebar (under "Security + networking")
7) Click "Access keys" in the left sidebar (under "Security + networking").
8) Look for the "Connection string" title under "key1". In the row below the
title, click "Show" to reveal the key. Click the copy icon or manually copy the
key, storing it in a safe place.
![Connection string "Show" button](pathname:///azure/connstr.png)
#### Container Setup
9) Click "Containers" in the left sidebar.
9) Click "Containers" in the left sidebar (under "Data storage").
10) Click "+ Container"
@ -617,7 +652,7 @@ S,h,e,e,t,J,S
21) Click on the name of the storage
22) In the middle column, click "Containers". It will be under "Data storage".
22) In the left sidebar, click "Containers". It will be under "Data storage".
23) Click on the name of the container in the table
@ -627,7 +662,9 @@ S,h,e,e,t,J,S
25) Click on the name `SheetJSBloblobber.xlsx`.
26) In the right pane, click "Download".
26) Click "Download" in the row below the file name:
![Download link in the website](pathname:///azure/dl.png)
The downloaded file is the raw file stored in Azure Blob Storage. To confirm it
is valid, open the file in Excel or another spreadsheet editor.

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
docz/static/azure/dl.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

@ -1,66 +1,48 @@
import React, { useRef } from "react";
import { utils, writeFileXLSX } from 'xlsx';
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableCell from '@mui/material/TableCell';
import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow';
import Paper from '@mui/material/Paper';
import { TableContainer, Table, TableRow, TableCell, TableBody, TableHead } from '@mui/material';
import { WorkBook, WorkSheet, read, utils, writeFileXLSX } from "xlsx";
import { useRef, useState, useEffect } from "react";
function createData(
name: string,
calories: number,
fat: number,
carbs: number,
protein: number,
) {
return { name, calories, fat, carbs, protein };
import './App.css'
interface President {
Name: string;
Index: number;
}
const rows = [
createData('Frozen yoghurt', 159, 6.0, 24, 4.0),
createData('Ice cream sandwich', 237, 9.0, 37, 4.3),
createData('Eclair', 262, 16.0, 24, 6.0),
createData('Cupcake', 305, 3.7, 67, 4.3),
createData('Gingerbread', 356, 16.0, 49, 3.9),
];
export default function BasicTable() {
function App() {
const tbl = useRef<HTMLTableElement>(null);
const xport = () => {
const wb: WorkBook = utils.table_to_book(tbl.current);
writeFileXLSX(wb, "SheetJSMaterialUI.xlsx");
};
const [pres, setPres] = useState<President[]>([]);
useEffect(() => {
let active = true;
(async() => {
const ab: ArrayBuffer = await (await fetch("https://docs.sheetjs.com/pres.xlsx")).arrayBuffer();
const wb: WorkBook = read(ab);
const ws: WorkSheet = wb.Sheets[wb.SheetNames[0]];
const aoo: President[] = utils.sheet_to_json<President>(ws);
if(active) setPres(aoo);
})();
return () => { active = false };
}, []);
return ( <>
<button onClick={() => {
const wb = utils.table_to_book(tbl.current);
writeFileXLSX(wb, "SheetJSMaterialUI.xlsx");
}}>Export</button>
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }} aria-label="simple table" ref={tbl}>
<TableHead>
<TableRow>
<TableCell>Dessert (100g serving)</TableCell>
<TableCell align="right">Calories</TableCell>
<TableCell align="right">Fat&nbsp;(g)</TableCell>
<TableCell align="right">Carbs&nbsp;(g)</TableCell>
<TableCell align="right">Protein&nbsp;(g)</TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows.map((row) => (
<TableRow
key={row.name}
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
>
<TableCell component="th" scope="row">
{row.name}
</TableCell>
<TableCell align="right">{row.calories}</TableCell>
<TableCell align="right">{row.fat}</TableCell>
<TableCell align="right">{row.carbs}</TableCell>
<TableCell align="right">{row.protein}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<button onClick={xport}>Export</button>
<TableContainer><Table ref={tbl}>
<TableHead><TableRow><TableCell>Name</TableCell><TableCell>Index</TableCell></TableRow></TableHead>
<TableBody>
{pres.map((row, idx) => (
<TableRow key={idx}>
<TableCell>{row.Name}</TableCell>
<TableCell>{row.Index}</TableCell>
</TableRow>
))}
</TableBody>
</Table></TableContainer>
</> );
}
}
export default App