forked from sheetjs/docs.sheetjs.com
		
	Google Sheets demo refresh
This commit is contained in:
		
							parent
							
								
									a5e01f9476
								
							
						
					
					
						commit
						55ce74bf8c
					
				| @ -81,6 +81,12 @@ do not work in MDX v2. Instead, string literals and concatenation must be used: | ||||
| <a href={"Foo" + current + ""}>{"Foo" + current + ""}</a> | ||||
| ``` | ||||
| 
 | ||||
| **Tables** | ||||
| 
 | ||||
| MDX inconsistently requires different indentation levels for `TD` / `TH`, `TR`, | ||||
| `THEAD` / `TBODY` / `TFOOT`, and `TABLE` tags. Unconventional indentation is | ||||
| intentional. | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -72,7 +72,11 @@ The script https://docs.sheetjs.com/dojo/dojo.js was fetched from the official | ||||
| 
 | ||||
| :::note Tested Deployments | ||||
| 
 | ||||
| The demos were last tested on 2023-12-04. | ||||
| This demo was tested in the following environments: | ||||
| 
 | ||||
| | Platform     | Date       | | ||||
| |:-------------|:-----------| | ||||
| | Chromium 125 | 2024-06-08 | | ||||
| 
 | ||||
| Demos exclusively using Dojo Core were tested using Dojo Toolkit `1.17.3`. | ||||
| 
 | ||||
|  | ||||
| @ -34,8 +34,8 @@ This demo was tested in the following environments: | ||||
| 
 | ||||
| | Version  | Date       | | ||||
| |:---------|:-----------| | ||||
| | `2.10.3` | 2023-12-04 | | ||||
| | `1.12.3` | 2023-12-04 | | ||||
| | `2.12.0` | 2024-06-08 | | ||||
| | `1.12.4` | 2024-06-08 | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| @ -135,7 +135,7 @@ main `index.html` page should load the `index.js` script: | ||||
| <body> | ||||
| <h3>SheetJS <span id="vers"></span> export demo</h3> | ||||
| <button id="xport">Click to Export!</button> | ||||
| <script src="index.js"></script> | ||||
| <script src="index.js" type="module"></script> | ||||
| <body> | ||||
| ``` | ||||
| 
 | ||||
| @ -208,7 +208,7 @@ yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} | ||||
| 3) Run the ParcelJS development server: | ||||
| 
 | ||||
| ```bash | ||||
| npx -y parcel@2.10.3 index.html | ||||
| npx -y parcel index.html | ||||
| ``` | ||||
| 
 | ||||
| The process will print a URL: | ||||
| @ -231,7 +231,7 @@ a web browser and click the "Click to Export!" button to generate a file. | ||||
| 6) Build the production site: | ||||
| 
 | ||||
| ```bash | ||||
| npx -y parcel@2.10.0 build index.html | ||||
| npx -y parcel build index.html | ||||
| ``` | ||||
| 
 | ||||
| The production site will be stored in the `dist` folder | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -32,7 +32,12 @@ flowchart LR | ||||
| 
 | ||||
| :::note Tested Deployments | ||||
| 
 | ||||
| This demo was last tested by SheetJS users on 2024-04-25 in Maple 2024. | ||||
| This demo was tested by SheetJS users in the following deployments: | ||||
| 
 | ||||
| | Architecture | Version | Date       | | ||||
| |:-------------|:--------|:-----------| | ||||
| | `darwin-x64` | 2024    | 2024-04-25 | | ||||
| | `win10-x64`  | 2024    | 2024-04-25 | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								docz/static/gsheet/SheetJS1.png
									
									
									
									
									
										Normal file
									
								
							
							
								
									
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								docz/static/gsheet/SheetJS1.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 13 KiB | 
							
								
								
									
										
											BIN
										
									
								
								docz/static/gsheet/SheetJS2.png
									
									
									
									
									
										Normal file
									
								
							
							
								
									
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								docz/static/gsheet/SheetJS2.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 25 KiB | 
							
								
								
									
										
											BIN
										
									
								
								docz/static/gsheet/creds.png
									
									
									
									
									
										Normal file
									
								
							
							
								
									
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								docz/static/gsheet/creds.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 55 KiB | 
							
								
								
									
										39
									
								
								docz/static/gsheet/dump.mjs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										39
									
								
								docz/static/gsheet/dump.mjs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | ||||
| import { google } from "googleapis"; | ||||
| 
 | ||||
| import { set_fs, writeFile, utils } from 'xlsx'; | ||||
| import * as fs from 'fs'; | ||||
| set_fs(fs); | ||||
| 
 | ||||
| /* Change this import statement to point to the credentials JSON file */ | ||||
| import creds from './sheetjs-test-726272627262.json' assert { type: "json" }; | ||||
| 
 | ||||
| /* Change this to the spreadsheet ID */ | ||||
| const id = "SOME-SPREADSHEETJS-ID"; | ||||
| 
 | ||||
| /* connect to google services */ | ||||
| const jwt = new google.auth.JWT({ | ||||
|   email: creds.client_email, | ||||
|   key: creds.private_key, | ||||
|   scopes: [ | ||||
|     'https://www.googleapis.com/auth/spreadsheets', | ||||
|     'https://www.googleapis.com/auth/drive.file', | ||||
|   ] | ||||
| }); | ||||
| 
 | ||||
| const sheets = google.sheets({ version: "v4", auth: jwt }); | ||||
| 
 | ||||
| /* get existing sheets */ | ||||
| const wsheet = await sheets.spreadsheets.get({spreadsheetId: id}); | ||||
| 
 | ||||
| /* create a workbook */ | ||||
| const wb = utils.book_new(); | ||||
| 
 | ||||
| for(let sheet of wsheet.data.sheets) { | ||||
|   const name = sheet.properties.title; | ||||
|   const res = await sheets.spreadsheets.values.get({ | ||||
|     spreadsheetId: id, | ||||
|     range: `'${name}'` | ||||
|   }); | ||||
|   utils.book_append_sheet(wb, utils.aoa_to_sheet(res.data.values), name); | ||||
| } | ||||
| writeFile(wb, "SheetJSExport.xlsb"); | ||||
							
								
								
									
										87
									
								
								docz/static/gsheet/init.mjs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										87
									
								
								docz/static/gsheet/init.mjs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,87 @@ | ||||
| import { google } from "googleapis"; | ||||
| 
 | ||||
| /* Change this import statement to point to the credentials JSON file */ | ||||
| import creds from './sheetjs-test-726272627262.json' assert { type: "json" }; | ||||
| 
 | ||||
| /* Change this to the primary account address, NOT THE SERVICE ACCOUNT */ | ||||
| const acct = "YOUR_ADDRESS@gmail.com"; | ||||
| 
 | ||||
| /* connect to google services */ | ||||
| const jwt = new google.auth.JWT({ | ||||
|   email: creds.client_email, | ||||
|   key: creds.private_key, | ||||
|   scopes: [ | ||||
|     'https://www.googleapis.com/auth/spreadsheets', | ||||
|     'https://www.googleapis.com/auth/drive.file', | ||||
|   ] | ||||
| }); | ||||
| 
 | ||||
| const sheets = google.sheets({ version: "v4", auth: jwt }); | ||||
| const drive = google.drive({version: "v3", auth: jwt }); | ||||
| 
 | ||||
| /* create new google workbook */ | ||||
| const [id, sheet0id] = await (async() => { | ||||
|   const res = await sheets.spreadsheets.create({ | ||||
|     requestBody: { | ||||
|       properties: { | ||||
|         title: "SheetJS Test" | ||||
|       } | ||||
|     } | ||||
|   }); | ||||
|   const id = res.data.spreadsheetId; | ||||
|   const sheet0id = res.data.sheets[0].properties.sheetId; | ||||
|   return [id, sheet0id]; | ||||
| })(); | ||||
| console.log(`Created Google Workbook ${id}`); | ||||
| 
 | ||||
| /* create new google worksheet and delete initial sheet */ | ||||
| const [sheet1id, sheet2id] = await (async() => { | ||||
|   const res = await sheets.spreadsheets.batchUpdate({ | ||||
|     spreadsheetId: id, | ||||
|     requestBody: { requests: [ | ||||
|       /* add SheetJS1 */ | ||||
|       { addSheet: { properties: { title: "SheetJS1" } } }, | ||||
|       /* add SheetJS2 */ | ||||
|       { addSheet: { properties: { title: "SheetJS2" } } }, | ||||
|       /* remove default sheet */ | ||||
|       { deleteSheet: { sheetId: sheet0id } }, | ||||
|     ] } | ||||
|   }); | ||||
|   console.log(`Created Google Worksheets "SheetJS1" and "SheetJS2"`); | ||||
|   return res.data.replies.slice(0,2).map(r => r.addSheet.properties.sheetId); | ||||
| })(); | ||||
| 
 | ||||
| await sheets.spreadsheets.values.update({ | ||||
|   spreadsheetId: id, | ||||
|   range: "SheetJS1!A1", | ||||
|   valueInputOption: "USER_ENTERED", | ||||
|   resource: { values: [ | ||||
|     ["Sheet", "JS"], | ||||
|     [72, 62] | ||||
|   ]} | ||||
| }); | ||||
| 
 | ||||
| await sheets.spreadsheets.values.update({ | ||||
|   spreadsheetId: id, | ||||
|   range: "SheetJS2!A1", | ||||
|   valueInputOption: "USER_ENTERED", | ||||
|   resource: { values: [ | ||||
|     ["Area Code", "Part 1", "Part 2"], | ||||
|     [201, 867, 5309], | ||||
|     [281, 330, 8004], | ||||
|   ]} | ||||
| }); | ||||
| 
 | ||||
| /* Share new Document with the primary account */ | ||||
| try { | ||||
|   await drive.permissions.create({ | ||||
|     fileId: id, | ||||
|     fields: "id", | ||||
|     requestBody: { | ||||
|       type: "user", | ||||
|       role: "writer", | ||||
|       emailAddress: acct | ||||
|     } | ||||
|   }); | ||||
|   console.log(`Shared ${id} with ${acct}`); | ||||
| } catch(e) { console.log(e); } | ||||
							
								
								
									
										87
									
								
								docz/static/gsheet/load.mjs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										87
									
								
								docz/static/gsheet/load.mjs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,87 @@ | ||||
| import { google } from "googleapis"; | ||||
| 
 | ||||
| import { set_fs, readFile, utils } from 'xlsx'; | ||||
| import * as fs from 'fs'; | ||||
| set_fs(fs); | ||||
| 
 | ||||
| /* Change this import statement to point to the credentials JSON file */ | ||||
| import creds from './sheetjs-test-726272627262.json' assert { type: "json" }; | ||||
| 
 | ||||
| /* Change this to the spreadsheet ID */ | ||||
| const id = "SOME-SPREADSHEETJS-ID"; | ||||
| 
 | ||||
| /* connect to google services */ | ||||
| const jwt = new google.auth.JWT({ | ||||
|   email: creds.client_email, | ||||
|   key: creds.private_key, | ||||
|   scopes: [ | ||||
|     'https://www.googleapis.com/auth/spreadsheets', | ||||
|     'https://www.googleapis.com/auth/drive.file', | ||||
|   ] | ||||
| }); | ||||
| 
 | ||||
| const sheets = google.sheets({ version: "v4", auth: jwt }); | ||||
| 
 | ||||
| /* get existing sheets */ | ||||
| const wsheet = await sheets.spreadsheets.get({spreadsheetId: id}); | ||||
| 
 | ||||
| /* remove all sheets after the first */ | ||||
| if(wsheet.data.sheets.length > 1) await sheets.spreadsheets.batchUpdate({ | ||||
|   spreadsheetId: id, | ||||
|   requestBody: { requests: | ||||
|     wsheet.data.sheets.slice(1).map(s => ({ | ||||
|       deleteSheet: { | ||||
|         sheetId: s.properties.sheetId | ||||
|       } | ||||
|     })) | ||||
|   } | ||||
| }); | ||||
| 
 | ||||
| /* read file */ | ||||
| const wb = readFile("pres.numbers"); | ||||
| 
 | ||||
| /* rename first worksheet to avoid collisions */ | ||||
| const props0 = wsheet.data.sheets[0].properties; | ||||
| if(wb.SheetNames.map(n => n.toLowerCase()).includes(props0.title.toLowerCase())) { | ||||
|   await sheets.spreadsheets.batchUpdate({ | ||||
|     spreadsheetId: id, | ||||
|     requestBody: { requests: [{ | ||||
|       updateSheetProperties: { | ||||
|         fields: "title", | ||||
|         properties: { | ||||
|           sheetId: props0.sheetId, | ||||
|           title: "thistitleisatleast33characterslong" | ||||
|         } | ||||
|       } | ||||
|     }]} | ||||
|   }); | ||||
|   console.log(`renamed "${props0.title}" to "thistitleisatleast33characterslong"`); | ||||
| } | ||||
| 
 | ||||
| /* add sheets from file */ | ||||
| for(let name of wb.SheetNames) { | ||||
|   const aoa = utils.sheet_to_json(wb.Sheets[name], {header:1}); | ||||
|   await sheets.spreadsheets.batchUpdate({ | ||||
|     spreadsheetId: id, | ||||
|     requestBody: { requests: [ | ||||
|       /* add new sheet */ | ||||
|       { addSheet: { properties: { title: name } } }, | ||||
|     ] } | ||||
|   }); | ||||
|   await sheets.spreadsheets.values.update({ | ||||
|     spreadsheetId: id, | ||||
|     range: `'${name}'!A1`, | ||||
|     valueInputOption: "USER_ENTERED", | ||||
|     resource: { values: aoa } | ||||
|   }); | ||||
|   console.log(`Created Google Worksheet "${name}"`); | ||||
| } | ||||
| 
 | ||||
| /* remove first sheet */ | ||||
| const res = await sheets.spreadsheets.batchUpdate({ | ||||
|   spreadsheetId: id, | ||||
|   requestBody: { requests: [ | ||||
|     /* remove old first sheet */ | ||||
|     { deleteSheet: { sheetId: wsheet.data.sheets[0].properties.sheetId } } | ||||
|   ] } | ||||
| }); | ||||
							
								
								
									
										
											BIN
										
									
								
								docz/static/gsheet/notification.png
									
									
									
									
									
										Normal file
									
								
							
							
								
									
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								docz/static/gsheet/notification.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 37 KiB | 
							
								
								
									
										38
									
								
								docz/static/gsheet/raw.mjs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										38
									
								
								docz/static/gsheet/raw.mjs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| import { google } from "googleapis"; | ||||
| 
 | ||||
| import { read, utils } from 'xlsx'; | ||||
| 
 | ||||
| /* Change this import statement to point to the credentials JSON file */ | ||||
| import creds from './sheetjs-test-726272627262.json' assert { type: "json" }; | ||||
| 
 | ||||
| /* Change this to the spreadsheet ID */ | ||||
| const id = "SOME-SPREADSHEETJS-ID"; | ||||
| 
 | ||||
| /* connect to google services */ | ||||
| const jwt = new google.auth.JWT({ | ||||
|   email: creds.client_email, | ||||
|   key: creds.private_key, | ||||
|   scopes: [ | ||||
|     'https://www.googleapis.com/auth/spreadsheets', | ||||
|     'https://www.googleapis.com/auth/drive.file', | ||||
|   ] | ||||
| }); | ||||
| 
 | ||||
| const drive = google.drive({ version: "v3", auth: jwt }); | ||||
| 
 | ||||
| /* get XLSX export */ | ||||
| const file = await drive.files.export({ | ||||
|   mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", | ||||
|   fileId: id | ||||
| }); | ||||
| const ab = await file.data.arrayBuffer(); | ||||
| 
 | ||||
| /* parse with SheetJS */ | ||||
| const wb = read(ab); | ||||
| 
 | ||||
| /* print CSV data from each worksheet */ | ||||
| wb.SheetNames.forEach(n => { | ||||
|   console.log(`#### ${n}`); | ||||
|   console.log(utils.sheet_to_csv(wb.Sheets[n])); | ||||
|   console.log(""); | ||||
| }) | ||||
							
								
								
									
										
											BIN
										
									
								
								docz/static/gsheet/selector.png
									
									
									
									
									
										Normal file
									
								
							
							
								
									
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								docz/static/gsheet/selector.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 50 KiB | 
							
								
								
									
										93
									
								
								tests/bundler-parcel.sh
									
									
									
									
									
										Executable file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										93
									
								
								tests/bundler-parcel.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,93 @@ | ||||
| #!/bin/bash | ||||
| # https://docs.sheetjs.com/docs/demos/frontend/bundler/parcel | ||||
| cd /tmp | ||||
| rm -rf sheetjs-parceljs | ||||
| 
 | ||||
| mkdir sheetjs-parceljs | ||||
| cd sheetjs-parceljs | ||||
| npm init -y | ||||
| 
 | ||||
| npm i --save https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz | ||||
| 
 | ||||
| cat >index.html <<EOF | ||||
| <body> | ||||
| <h3>SheetJS <span id="vers"></span> export demo</h3> | ||||
| <button id="xport">Click to Export!</button> | ||||
| <script src="index.js" type="module"></script> | ||||
| <body> | ||||
| EOF | ||||
| 
 | ||||
| cat >index.js <<EOF | ||||
| // ESM-style import from "xlsx" | ||||
| import { utils, version, writeFileXLSX } from 'xlsx'; | ||||
| 
 | ||||
| document.getElementById("vers").innerText = version; | ||||
| document.getElementById("xport").onclick = async() => { | ||||
|   /* fetch JSON data and parse */ | ||||
|   const url = "https://docs.sheetjs.com/executive.json"; | ||||
|   const raw_data = await (await fetch(url)).json(); | ||||
| 
 | ||||
|   /* filter for the Presidents */ | ||||
|   const prez = raw_data.filter(row => row.terms.some(term => term.type === "prez")); | ||||
| 
 | ||||
|   /* sort by first presidential term */ | ||||
|   prez.forEach(row => row.start = row.terms.find(term => term.type === "prez").start); | ||||
|   prez.sort((l,r) => l.start.localeCompare(r.start)); | ||||
| 
 | ||||
|   /* flatten objects */ | ||||
|   const rows = prez.map(row => ({ | ||||
|     name: row.name.first + " " + row.name.last, | ||||
|     birthday: row.bio.birthday | ||||
|   })); | ||||
| 
 | ||||
|   /* generate worksheet and workbook */ | ||||
|   const worksheet = utils.json_to_sheet(rows); | ||||
|   const workbook = utils.book_new(); | ||||
|   utils.book_append_sheet(workbook, worksheet, "Dates"); | ||||
| 
 | ||||
|   /* fix headers */ | ||||
|   utils.sheet_add_aoa(worksheet, [["Name", "Birthday"]], { origin: "A1" }); | ||||
| 
 | ||||
|   /* calculate column width */ | ||||
|   const max_width = rows.reduce((w, r) => Math.max(w, r.name.length), 10); | ||||
|   worksheet["!cols"] = [ { wch: max_width } ]; | ||||
| 
 | ||||
|   /* create an XLSX file and try to save to Presidents.xlsx */ | ||||
|   writeFileXLSX(workbook, "Presidents.xlsx"); | ||||
| }; | ||||
| EOF | ||||
| 
 | ||||
| cat >test.js <<EOF | ||||
| const puppeteer = require('puppeteer'); | ||||
| const express = require('express'); | ||||
| const app = express(); | ||||
| app.use(express.static('./dist')); | ||||
| app.listen(7262, async() => { | ||||
|   await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   const browser = await puppeteer.launch(); | ||||
|   const page = await browser.newPage(); | ||||
|   page.on("console", msg => console.log("PAGE LOG:", msg.text())); | ||||
|   await page.setViewport({width: 1920, height: 1080}); | ||||
|   const client = await page.target().createCDPSession(); | ||||
|   await client.send('Browser.setDownloadBehavior', { | ||||
|     behavior: 'allow', | ||||
|     downloadPath: require("path").resolve('./') | ||||
|   }); | ||||
|   page.on('request', req => console.log(req.url())); | ||||
|   await page.goto('http://localhost:7262/'); | ||||
|   await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   await page.click("#xport"); | ||||
|   await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   await browser.close(); | ||||
|   process.exit(); | ||||
| }); | ||||
| EOF | ||||
| 
 | ||||
| node -e 'var pjson = JSON.parse(fs.readFileSync("./package.json")); console.log(pjson); delete pjson.main; fs.writeFileSync("package.json", JSON.stringify(pjson))' | ||||
| 
 | ||||
| for n in 1.12.4 2.12.0; do | ||||
|   npx -y parcel build index.html | ||||
|   node test.js | ||||
|   npx -y xlsx-cli Presidents.xlsx | head -n 3 | ||||
|   rm -f Presidents.xlsx | ||||
| done | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user