diff --git a/docz/docs/03-demos/09-cloud/02-netsuite.md b/docz/docs/03-demos/09-cloud/02-netsuite.md index 86317d5..f7c2679 100644 --- a/docz/docs/03-demos/09-cloud/02-netsuite.md +++ b/docz/docs/03-demos/09-cloud/02-netsuite.md @@ -25,7 +25,7 @@ This demo was verified by NetSuite consultants in the following deployments: | `@NScriptType` | `@NApiVersion` | Date | |:----------------|:---------------|:-----------| | ScheduledScript | 2.1 | 2023-08-18 | -| Restlet | 2.1 | 2023-04-20 | +| Restlet | 2.1 | 2023-10-05 | | Suitelet | 2.1 | 2023-07-21 | | MapReduceScript | 2.1 | 2023-07-31 | diff --git a/docz/docs/03-demos/09-cloud/11-aws.md b/docz/docs/03-demos/09-cloud/11-aws.md index 647b2b8..83158fb 100644 --- a/docz/docs/03-demos/09-cloud/11-aws.md +++ b/docz/docs/03-demos/09-cloud/11-aws.md @@ -311,7 +311,7 @@ Function properties. 17) Select the "Configuration" tab and select "Permissions" in the left sidebar. -18) Scroll down to "Resource-based policy statements" and ensure that +18) Scroll down to "Resource-based policy statements" and ensure that `FunctionURLAllowPublicAccess` is listed. If no policy statements are defined, select "Add Permission" with the options: @@ -373,7 +373,7 @@ var s3 = new AWS.S3({ ``` -### Reading Data +### Downloading Data #### Fetching Files from S3 @@ -425,7 +425,7 @@ stream.on('end', function() { }); ``` -### Writing Data +### Uploading Data The SheetJS `write` method[^13] with the option `type: "buffer"` will generate NodeJS Buffers. `S3#upload` directly accepts these Buffer objects. diff --git a/docz/docs/03-demos/09-cloud/12-azure.md b/docz/docs/03-demos/09-cloud/12-azure.md index bf71e7b..5cca6b2 100644 --- a/docz/docs/03-demos/09-cloud/12-azure.md +++ b/docz/docs/03-demos/09-cloud/12-azure.md @@ -5,10 +5,26 @@ pagination_next: demos/extensions/index --- import current from '/version.js'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock'; -Azure is a Cloud Services platform which includes traditional virtual machine -support, "Serverless Functions", cloud storage and much more. +[Azure Cloud Services](https://azure.microsoft.com/) is a Cloud Services +platform which includes traditional virtual machine support, "Serverless +Functions" and cloud storage. + +[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing +data from spreadsheets. + +This demo explores two key AWS offerings: + +- ["Azure Functions"](#azure-functions) ("Lambda") explores the serverless + computing offering. The demo creates a JavaScript function that can process + user-submitted files and generate spreadsheets. + +- ["Blob Storage"](#blob-storage) explores the cloud storage offering. The demo + uses the NodeJS connection library to read spreadsheets from storage and write + spreadsheets back to cloud storage. :::caution pass @@ -17,22 +33,77 @@ will be available in the future. ::: -This demo focuses on two key offerings: cloud storage ("Azure Blob Storage") -and the "Serverless Function" platform ("Azure Functions"). - :::note -This demo was last tested on 2023 April 29. +This demo was last tested on 2023 October 06. ::: +## Telemetry + +:::warning Telemetry + +**Each command-line tool related to Azure embeds telemetry.** + +Azure tools embed telemetry without proper disclaimer. + +::: + +It is strongly recommended to disable telemetry before working with Azure. + +#### Azure Functions Core Tools + +Azure Functions Core Tools (`func`) telemetry is controlled through the +`FUNCTIONS_CORE_TOOLS_TELEMETRY_OPTOUT` environment variable. + + + + +Add the following line to `.profile`, `.bashrc` and `.zshrc`: + +```bash +export FUNCTIONS_CORE_TOOLS_TELEMETRY_OPTOUT=1 +``` + +Close and restart the Terminal to load the changes. + + + + +Type `env` in the search bar and select "Edit the system environment variables". + +In the new window, click the "Environment Variables..." button. + +In the new window, look for the "System variables" section and click "New..." + +Set the "Variable name" to `FUNCTIONS_CORE_TOOLS_TELEMETRY_OPTOUT` and the value +to `1`. + +Click "OK" in each window (3 windows) and restart your computer. + + + + +#### Azure CLI + +Azure CLI (`az`) telemetry can be disabled using a subcommand (after installing +the CLI tool)[^1]: + +```bash +az configure -d collect_telemetry=false +``` + ## Azure Functions +The [SheetJS NodeJS module](/docs/getting-started/installation/nodejs) can be +required in Azure Functions that use the NodeJS runtime. + This discussion focuses on the "HTTP Trigger" function type. -:::info pass +:::note pass -To enable binary data processing, a setting must be changed in `function.json`: +In earlier tests, to enable binary data processing, `function.json` required a +`dataType` option: ```json title="function.json" { @@ -45,150 +116,295 @@ To enable binary data processing, a setting must be changed in `function.json`: "name": "req", ``` +In the most recent test, the template did not create a `function.json` and the +option was not required. + ::: ### Reading Data -`formidable` expects a stream and Azure does not present one. It can be made: +Using `@azure/functions`, the handler callback receives a `Request` object. With +standard JS operations, the file can be pulled into an `ArrayBuffer` object. + +The SheetJS `read` method[^2] can read the `ArrayBuffer` objects and generate +SheetJS workbook objects[^3] which can be processed with other API functions. + +For example, a handler can use `sheet_to_csv`[^4] to generate CSV text: ```js +const { Blob } = require('buffer'); +const { app } = require('@azure/functions'); const XLSX = require('xlsx'); -const formidable = require('formidable'); -const Readable = require('stream').Readable; -/* formidable expects the request object to be a stream */ -const streamify = (req) => { - if(typeof req.on !== 'undefined') return req; - const s = new Readable(); - s._read = ()=>{}; - s.push(Buffer.from(req.body)); - s.push(null); - Object.assign(s, req); - return s; -}; +app.http('SheetJSAzure', { + methods: ['POST'], + handler: async (req, context) => { + /* grab the file at form key `upload` */ + const formData = await req.formData(); + const f = formData.get("upload"); -module.exports = (context, req) => { - const form = new formidable.IncomingForm(); - form.parse(streamify(req), (err, fields, files) => { - /* grab the first file */ - var f = files["upload"]; - if(!f) { - context.res = { status: 400, body: "Must submit a file for processing!" }; - } else { - /* file is stored in a temp directory, so we can point to that and read it */ - const wb = XLSX.read(f.filepath, {type:"file"}); + if(!(f instanceof Blob)) return { status: 400, body: "Must submit a file" }; - /* generate CSV from first sheet */ - const csv = XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]); - context.res = { status: 200, body: csv }; - } - context.done(); - }); -} + /* parse file */ + const ab = await f.arrayBuffer(); + const wb = XLSX.read(ab); + + /* generate CSV from first sheet */ + const ws = wb.Sheets[wb.SheetNames[0]]; + const csv = XLSX.utils.sheet_to_csv(ws); + return { status: 200, body: csv }; + } +}); ``` ### Writing Data -The `body` property can be a Buffer, like those generated by `XLSX.write`: +The SheetJS `write` method[^5] with the option `type: "buffer"` will generate +NodeJS buffers which can be sent in the callback handler response. + +The following example generates a sample worksheet using the `aoa_to_sheet`[^6] +method, generates a sample workbook using worksheet helper methods[^7], writes +the workbook to XLSX format in a Buffer, and sends the Buffer in the response: ```js +const { app } = require('@azure/functions'); const XLSX = require('xlsx'); -module.exports = (context, req) => { - // generate XLSX file in a Buffer - var ws = XLSX.utils.aoa_to_sheet(["SheetJS".split(""), [5,4,3,3,7,9,5]]); - var wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Data"); - // highlight-next-line - var buf = XLSX.write(wb, {type: "buffer", bookType: "xlsx"}); - // Set the body and Content-Disposition header - // highlight-start - context.res = { - status: 200, - headers: { "Content-Disposition": `attachment; filename="SheetJSAzure.xlsx";` }, - body: buf - }; - // highlight-end - context.done(); -}; +app.http('SheetJSAzure', { + methods: ['GET'], + handler: async (req, context) => { + /* generate sample worksheet */ + var ws = XLSX.utils.aoa_to_sheet(["SheetJS".split(""), [5, 4, 3, 3, 7, 9, 5]]); + /* generate workbook */ + var wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Data"); + /* write to XLSX, returning a NodeJS Buffer */ + var buf = XLSX.write(wb, { type: "buffer", bookType: "xlsx" }); + /* send Buffer to client */ + return { + status: 200, + /* Content-Disposition header */ + headers: { "Content-Disposition": `attachment; filename="SheetJSAzure.xlsx";` }, + /* data */ + body: buf + }; + } +}); ``` -### Demo +### Functions Demo -
Complete Example (click to show) +:::note pass -0) Review the quick start for JavaScript on Azure Functions. This involves -installing the Azure Functions Core Tools and other dependencies. +At the time of writing, the Azure Free Tier included an allowance of 1 million +free requests per month. -1) Create a new project and install dependencies: +::: + +0) If you do not have an account, create a new Azure free tier account[^8]. + +#### Local Setup + +1) [Disable Azure Functions Core Tools Telemetry](#azure-functions-core-tools). + +2) Install the CLI tool using npm: + +```bash +npm i -g azure-functions-core-tools@4 --unsafe-perm true +``` + +:::note pass + +On macOS and Linux, `sudo` may be required: + +```bash +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) + +4) Disable Azure CLI telemetry: + +```bash +az configure -d collect_telemetry=false +``` + +#### Start Project + +5) Create a new JavaScript HTTP Trigger project: + +```bash +mkdir SheetJSAzure +cd SheetJSAzure +func new --template httpTrigger --language JavaScript --name SheetJSAzure +``` + +:::warning pass + +When the demo was last tested, the stock TypeScript template did not work. + +**This is a bug in the Azure Functions Core Tools** + +Until the bugs are resolved, JavaScript should be preferred over TypeScript. + +::: + +6) Start the local server: + +```bash +npm start +``` + +7) While the server is running, open a new terminal window and make a request: + +```bash +curl -L http://localhost:7071/api/SheetJSAzure +``` + +The terminal should display `Hello, world!` + +#### Add SheetJS + +8) Install the SheetJS NodeJS module: {`\ -func init sheetjs-azure --worker-runtime node --language javascript -cd sheetjs-azure -npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz formidable`} +npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} -2) Create a new "HTTP Trigger" function: +9) Download [the sample script](pathname:///azure/index.js): ```bash -func new --template "Http Trigger" --name SheetJSAzure +curl -L -o src/functions/SheetJSAzure.js https://docs.sheetjs.com/azure/index.js ``` -3) Edit `SheetJSAzure/function.json` to add the `dataType: "binary"` property: +#### Local Test -```js title="SheetJSAzure/function.json" - "direction": "in", -// highlight-next-line - "dataType": "binary", - "name": "req", -``` - -4) Download [`SheetJSAzure/index.js`](pathname:///aws/index.js): +10) Stop and restart the dev server: ```bash -curl -L -o SheetJSAzure/index.js https://docs.sheetjs.com/azure/index.js +npm start ``` -5) Test locally with `npm start` - -To test uploads, download and run: +11) In a separate terminal window, download +and make a POST request to the dev server: ```bash curl -LO https://sheetjs.com/pres.numbers curl -X POST -F "upload=@pres.numbers" http://localhost:7071/api/SheetJSAzure ``` -To test downloads, access `http://localhost:7071/api/SheetJSAzure` and download -the generated file. Confirm it is a valid file. +If the test succeeded, the terminal will print CSV rows from the test file data. -6) Deploy to Azure. Replace `NAME_OF_FUNCTION_APP` with the name: +12) Open a web browser and access `http://localhost:7071/api/SheetJSAzure` . -```bash -func azure functionapp publish NAME_OF_FUNCTION_APP +If the test succeeded, the browser will attempt to download `SheetJSAzure.xlsx`. +Open in Excel or another spreadsheet editor to confirm the file is valid. + +#### Create Remote Function + +13) Sign into the [Azure Portal](https://portal.azure.com/#home) + +14) Type "Function App" in the top search box and click "Function App" + +15) Click "+ Create" + +16) Select the following options: + +- Type a memorable "Function Name" ("sheetjsazure" when last tested) + +- "Do you want to deploy code or container image?": select "Code" + +- "Runtime stack": select NodeJS + +- "Hosting options and plans": "Consumption (Serverless)" + +17) Click "Review + create", then click "Create" to create the function. + +The page will display a status message + +> ... Deployment is in progress + +When the resources are configured, the status will change to + +> Your deployment is complete + +18) Click "Go to Resource". + +19) Take note of the URL from the table + +#### Deploy to Azure + +20) Sign into Azure: + +``` +az login ``` -Get the function URL and test using the same sequence as in step 5. +The login flow resumes in the browser. -
+21) Deploy to Azure. Replace `FUNCTION_NAME` with the name from Step 16: -## Azure Blob Storage +```bash +func azure functionapp publish FUNCTION_NAME +``` + +After publishing, the process will print the "Invoke url": + +``` +Functions in sheetjsazure: + SheetJSAzure - [httpTrigger] +// highlight-next-line + Invoke url: https://sheetjsazure.azurewebsites.net/api/sheetjsazure +``` + +Take note of that URL. + +#### Remote Test + + +22) In a separate terminal window, download +and make a POST request to the production server. Replace `FUNCTION_URL` with +the Invoke URL from Step 21: + +```bash +curl -LO https://sheetjs.com/pres.numbers +curl -X POST -F "upload=@pres.numbers" FUNCTION_URL +``` + +If the test succeeded, the terminal will print CSV rows from the test file data. + +23) Open a web browser and access the Invoke URL from Step 21. + +If the test succeeded, the browser will attempt to download `SheetJSAzure.xlsx`. +Open in Excel or another spreadsheet editor to confirm the file is valid. + +## Blob Storage The main module for Azure Blob Storage is `@azure/storage-blob`. This example was tested using the "Connection String" authentication method. The strings are found in the Azure Portal under "Access Keys" for the storage account. -### Reading Data +### Downloading Data The `BlobClient#download` method returns a Stream. After collecting into a -Buffer, `XLSX.read` can parse the data: +Buffer, the SheetJS `read` method[^9] can parse the data into a workbook[^10]. + +The following demo uses the `sheet_to_csv`[^11] utility function to display the +contents of a file in Azure Blob Storage: ```js title="SheetJSReadFromAzure.mjs" import { BlobServiceClient } from "@azure/storage-blob"; import { read, utils } from "xlsx"; /* replace these constants */ +// highlight-start const connStr = ""; const containerName = ""; -const blobName = ""; +// highlight-end + +/* Blob name */ +const blobName = "SheetJSBloblobber.xlsx"; /* get a readable stream*/ const blobServiceClient = BlobServiceClient.fromConnectionString(connStr); @@ -207,18 +423,27 @@ const wb = read(downloaded); console.log(utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])); ``` -### Writing Data +### Uploading Data -`BlockBlobClient#upload` directly accepts a Buffer: +The SheetJS `write` method[^12] with the option `type: "buffer"` will generate +NodeJS buffers which can be uploaded with `BlockBlobClient#upload`. + +The following example generates a sample worksheet using the `aoa_to_sheet`[^13] +method, generates a sample workbook using worksheet helper methods[^14], writes +the workbook to XLSX format in a Buffer, and sends the Buffer in the response: ```js title="SheetJSWriteToAzure.mjs" import { BlobServiceClient } from "@azure/storage-blob"; import { write, utils } from "xlsx"; /* replace these constants */ +// highlight-start const connStr = ""; const containerName = ""; -const blobName = ""; +// highlight-end + +/* Blob name */ +const blobName = "SheetJSBloblobber.xlsx"; /* Create a simple workbook and write XLSX to buffer */ const ws = utils.aoa_to_sheet(["SheetJS".split(""), [5,4,3,3,7,9,5]]); @@ -231,3 +456,165 @@ const containerClient = blobServiceClient.getContainerClient(containerName); const blockBlobClient = containerClient.getBlockBlobClient(blobName); const uploadBlobResponse = await blockBlobClient.upload(buf, buf.length); ``` + +### Blob Demo + +:::note pass + +At the time of writing, new Azure accounts were granted a 12-month trial of Blob +Storage. The trial includes 5GB of "Locally-redundant storage" with 20,000 read +requests and 2000 write requests per month. + +::: + +0) If you do not have an account, create a new Azure free tier account[^8]. + +#### Storage Account Setup + +1) Sign into the [Azure Portal](https://portal.azure.com/#home) + +2) Type "Storage" in the top search box and click "Storage accounts" + +3) Click "+ Create" + +4) Select the following options: + +- Type a memorable "Storage account name" ("sheetjstorage" when last tested) + +- "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 + +> ... Deployment is in progress + +When the resources are configured, the status will change to + +> Your deployment is complete + +6) Click "Go to Resource". + +#### Access Keys + +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. + +#### Container Setup + +9) Click "Containers" in the left sidebar. + +10) Click "+ Container" + +11) Select the following options: + +- Type a memorable "Name" ("sheetjs-container" when last tested) + +12) Click "Create" to create the container. + +#### Project Setup + +13) Create a new project folder: + +```bash +mkdir SheetJSBlob +cd SheetJSBlob +npm init -y +``` + +14) Install dependencies: + +{`\ +npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @azure/storage-blob`} + + +14) Copy the [`SheetJSReadFromAzure.mjs` code block](#downloading-data) and save +to `SheetJSReadFromAzure.mjs`. + +15) Copy the [`SheetJSWriteToAzure.mjs` code block](#uploading-data) and save +to `SheetJSWriteToAzure.mjs`. + +16) Edit both `SheetJSReadFromAzure.mjs` and `SheetJSWriteToAzure.mjs`: + +- Replace the `connStr` value with the connection string from Step 8 +- Replace the `containerName` value with the container name from Step 11 + +#### Test + +:::note pass + +The write demo creates a simple workbook, generates a NodeJS buffer, and uploads +the buffer to a file named `SheetJSBloblobber.xlsx` on Azure Blob Storage. + +The read demo fetches `SheetJSBloblobber.xlsx` and displays the data. + +``` + | A | B | C | D | E | F | G | +---+---|---|---|---|---|---|---| + 1 | S | h | e | e | t | J | S | + 2 | 5 | 4 | 3 | 3 | 7 | 9 | 5 | +``` + +::: + +17) Run the write test: + +```bash +node SheetJSWriteToAzure.mjs +``` + +This will write the file `SheetJSBloblobber.xlsx` to the container. + +18) Run the read test: + +```bash +node SheetJSReadFromAzure.mjs +``` + +It will fetch the file created in the previous step and display CSV rows. + +``` +S,h,e,e,t,J,S +5,4,3,3,7,9,5 +``` + +19) Sign into the [Azure Portal](https://portal.azure.com/#home) + +20) Type "Storage" in the top search box and click "Storage accounts" + +21) Click on the name of the storage + +22) In the middle column, click "Containers". It will be under "Data storage". + +23) Click on the name of the container in the table + +24) Verify that the table shows `SheetJSBloblobber.xlsx`: + +![SheetJSBloblobber.xlsx in the container](pathname:///azure/bloblobber.png) + +25) Click on the name `SheetJSBloblobber.xlsx`. + +26) In the right pane, click "Download". + +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. + +[^1]: The platform-specific installers are available at +[^2]: See [`read` in "Reading Files"](/docs/api/parse-options) +[^3]: See ["Workbook Object" in "SheetJS Data Model"](/docs/csf/book) for more details. +[^4]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output) +[^5]: See [`write` in "Writing Files"](/docs/api/write-options) +[^6]: See [`aoa_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-arrays-input) +[^7]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`. +[^8]: Registering for a free account [on the Azure Free Tier](https://azure.microsoft.com/en-us/free) requires a valid phone number and a valid credit card. +[^9]: See [`read` in "Reading Files"](/docs/api/parse-options) +[^10]: See ["Workbook Object" in "SheetJS Data Model"](/docs/csf/book) for more details. +[^11]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output) +[^12]: See [`write` in "Writing Files"](/docs/api/write-options) +[^13]: See [`aoa_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-arrays-input) +[^14]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`. diff --git a/docz/docs/index.md b/docz/docs/index.md index 3ce90e4..a13eaf7 100644 --- a/docz/docs/index.md +++ b/docz/docs/index.md @@ -5,6 +5,8 @@ title: Overview --- import current from '/version.js'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock'; # SheetJS CE @@ -27,6 +29,9 @@ run entirely in the web browser.
How to add to your site (click to show) + + + 1) Make sure your table has an ID: ```html @@ -45,7 +50,7 @@ run entirely in the web browser. ``` -4) Add an event handler for the `click` event to create a workbook and download: +4) Add an event handler for the `click` event to export table data to XLSX: ```html ``` + + + +:::note pass + +This example assumes you have an existing project with an HTML TABLE element: + +```jsx title="Sample Component" +function App() { + return ( <> +

SheetJS Table

+ + + + + +
SheetJS Table Export
AuthorID你好!
SheetJS7262வணக்கம்!
+ Powered by SheetJS +
+ ) +} +export default App; +``` + +If you are starting from scratch, create a new ViteJS + ReactJS project: + +```bash +npm create vite@latest -- sheetjs-react --template react --default +cd sheetjs-react +npm install +npm run dev +``` + +Replace `src/App.jsx` with the sample component. + +::: + +1) Install the SheetJS library using a package manager: + + + +{`\ +npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} + + + +{`\ +pnpm install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} + + + +{`\ +yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} + + + + +2) Ensure that your component script imports `useRef` from the `react` library: + +```js +import { useRef } from "react"; +``` + +3) Add the following line at the top of your component script: + +```js +import { utils, writeFileXLSX } from "xlsx"; +``` + +4) Create a ref in the body of your function component: + +```jsx +function App() { +// highlight-next-line + const tbl = useRef(null); + // ... +``` + +5) Attach the ref to the table element: + +```jsx +function App() { + // ... + return ( + {/*...*/} +// highlight-next-line + + {/*...*/} +``` + +6) Add a button with a click handler that will export table data to XLSX: + +```jsx +function App() { + // ... + return ( + {/*...*/} +// highlight-start + +// highlight-end + {/*...*/} +``` + + + +
How to automate with NodeJS (click to show) @@ -74,7 +190,7 @@ using the `puppeteer` and `playwright` browser automation frameworks. function Table2XLSX(props) { /* Callback invoked when the button is clicked */ - const xport = React.useCallback(async () => { + const xport = React.useCallback(() => { /* Create worksheet from HTML DOM TABLE */ const table = document.getElementById("Table2XLSX"); const wb = XLSX.utils.table_to_book(table); diff --git a/docz/docusaurus.config.js b/docz/docusaurus.config.js index c283b59..bb7c94c 100644 --- a/docz/docusaurus.config.js +++ b/docz/docusaurus.config.js @@ -202,6 +202,7 @@ const config = { { from: '/docs/demos/hosting/dropbox', to: '/docs/demos/cloud/dropbox/' }, { from: '/docs/demos/hosting/github', to: '/docs/demos/cloud/github/' }, /* data */ + { from: '/docs/getting-started/demos/database', to: '/docs/demos/data/' }, { from: '/docs/demos/database', to: '/docs/demos/data/' }, { from: '/docs/demos/nosql', to: '/docs/demos/data/' }, { from: '/docs/getting-started/demos/nosql', to: '/docs/demos/data/' }, diff --git a/docz/static/azure/bloblobber.png b/docz/static/azure/bloblobber.png new file mode 100644 index 0000000..182ef1d Binary files /dev/null and b/docz/static/azure/bloblobber.png differ diff --git a/docz/static/azure/index.js b/docz/static/azure/index.js index b20ed83..38aa42e 100644 --- a/docz/static/azure/index.js +++ b/docz/static/azure/index.js @@ -1,49 +1,38 @@ /* sheetjs (C) SheetJS -- https://sheetjs.com */ +const { Blob } = require('buffer'); +const { app } = require('@azure/functions'); const XLSX = require('xlsx'); -const formidable = require('formidable'); -const Readable = require('stream').Readable; -/* formidable expects the request object to be a stream */ -const streamify = (req) => { - if(typeof req.on !== 'undefined') return req; - const s = new Readable(); - s._read = ()=>{}; - s.push(Buffer.from(req.body)); - s.push(null); - Object.assign(s, req); - return s; -}; +app.http('SheetJSAzure', { + methods: ['GET', 'POST'], + authLevel: 'anonymous', + handler: async (req, context) => { + if (req.method == "POST") { + /* grab the file at form key `upload` */ + const formData = await req.formData(); + const f = formData.get("upload"); -module.exports = (context, req) => { - if(req.method == "POST") { - const form = new formidable.IncomingForm(); - form.parse(streamify(req), (err, fields, files) => { - /* grab the first file */ - var f = files["upload"]; - if(!f) { - context.res = { status: 400, body: "Must submit a file for processing!" }; + if (!f || !(f instanceof Blob)) { + return { status: 400, body: "Must submit a file for processing!" }; } else { - /* file is stored in a temp directory, so we can point to that and read it */ - const wb = XLSX.read(f.filepath, {type:"file"}); + /* parse file */ + const ab = await f.arrayBuffer(); + const wb = XLSX.read(ab); /* generate CSV from first sheet */ const csv = XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]); - context.res = { status: 200, body: csv }; + return { status: 200, body: csv }; } - context.done(); - }); - } else if(req.method == "GET") { - var ws = XLSX.utils.aoa_to_sheet(["SheetJS".split(""), [5,4,3,3,7,9,5]]); - var wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Data"); - var buf = XLSX.write(wb, {type: "buffer", bookType: "xlsx"}); - context.res = { - status: 200, - headers: { "Content-Disposition": `attachment; filename="SheetJSAzure.xlsx";` }, - body: buf - }; - context.done(); - } else { - context.res = { status: 500, body: `Unsupported method ${req.method}` }; - context.done(); + + } else if (req.method == "GET") { + var ws = XLSX.utils.aoa_to_sheet(["SheetJS".split(""), [5, 4, 3, 3, 7, 9, 5]]); + var wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Data"); + var buf = XLSX.write(wb, { type: "buffer", bookType: "xlsx" }); + return { + status: 200, + headers: { "Content-Disposition": `attachment; filename="SheetJSAzure.xlsx";` }, + body: buf + }; + } else return { status: 500, body: `Unsupported method ${req.method}` }; } -}; \ No newline at end of file +}); \ No newline at end of file diff --git a/docz/static/sqlite/chinook.sql b/docz/static/sqlite/chinook.sql index 4d35770..2680dc6 100644 --- a/docz/static/sqlite/chinook.sql +++ b/docz/static/sqlite/chinook.sql @@ -1,11 +1,11 @@ /* Licensing Note: - At the time this extract was made (2023 May 28), the linked license page + At the time this snapshot was taken, the linked license page http://www.codeplex.com/ChinookDatabase/license - was unavailable (Microsoft shuttered CodePlex). + was unavailable (Microsoft shuttered CodePlex in 2021) archive.org has a snapshot of the project license page: