update webpack, update packages, dev experience

update webpack, clasp, client code, eslint, prettier, readme, packages to latest
This commit is contained in:
Elisha Nuchi
2020-05-03 05:12:50 -04:00
parent f898046c06
commit 0ea874e8b4
30 changed files with 1978 additions and 2851 deletions
+29 -7
View File
@@ -1,8 +1,12 @@
{
"root": true,
"parser": "babel-eslint",
"extends": ["airbnb-base", "plugin:react/recommended", "eslint:recommended"],
"plugins": ["babel", "react"],
"extends": [
"airbnb-base",
"plugin:prettier/recommended",
"plugin:react/recommended"
],
"plugins": ["babel", "react", "prettier"],
"env": {
"browser": true,
"es6": true
@@ -12,11 +16,29 @@
"alert": false,
"css": true
},
"parserOptions": {
"ecmaVersion": 9,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"rules": {
"import/prefer-default-export": 0,
"no-console": 0,
"require-jsdoc": 0,
"no-invalid-this": 0,
"babel/no-invalid-this": 0
"prettier/prettier": "error",
"react/prop-types": "warn",
"camelcase": "warn",
"import/prefer-default-export": "warn",
"import/no-extraneous-dependencies": "warn",
"prefer-object-spread": "warn"
},
"settings": {
"react": {
"version": "detect"
},
"import/resolver": {
"node": {
"extensions": [".js", ".jsx"]
}
}
}
}
+5
View File
@@ -0,0 +1,5 @@
import React from 'react';
import ReactDOM from 'react-dom';
import About from './components/About';
ReactDOM.render(<About />, document.getElementById('index'));
+7
View File
@@ -0,0 +1,7 @@
import React from 'react';
import ReactDOM from 'react-dom';
import SheetEditor from './components/SheetEditor';
import './styles.css';
ReactDOM.render(<SheetEditor />, document.getElementById('index'));
-8
View File
@@ -1,8 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import {AboutPage} from './components/about-sidebar';
ReactDOM.render(
<AboutPage />,
document.getElementById('index')
);
@@ -1,6 +1,6 @@
import React from 'react';
export const AboutPage = () => (
const About = () => (
<div className="sheetNameText">
<div>Github repo:</div>
<a
@@ -13,3 +13,5 @@ export const AboutPage = () => (
<div>-Elisha Nuchi</div>
</div>
);
export default About;
@@ -1,7 +1,7 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
export default function FormInput(props) {
const FormInput = ({ newSheetFormHandler }) => {
const [text, setText] = useState('');
const handleChange = event => setText(event.target.value);
@@ -10,7 +10,7 @@ export default function FormInput(props) {
event.preventDefault();
if (text.length === 0) return;
props.newSheetFormHandler(event, text);
newSheetFormHandler(event, text);
setText('');
};
@@ -22,7 +22,9 @@ export default function FormInput(props) {
</form>
</div>
);
}
};
export default FormInput;
FormInput.propTypes = {
newSheetFormHandler: PropTypes.func,
@@ -1,9 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
const SheetButton = props => {
const { name, deleteButtonHandler, clickSheetNameHandler } = props;
const SheetButton = ({ name, deleteButtonHandler, clickSheetNameHandler }) => {
const { sheetIndex, text, isActive } = name;
return (
@@ -11,7 +9,7 @@ const SheetButton = props => {
<button onClick={e => deleteButtonHandler(e, sheetIndex)}>X</button>
<span
onClick={e => clickSheetNameHandler(e, text)}
className={'sheetNameText ' + (isActive ? 'active-sheet' : '')}
className={`sheetNameText ${isActive ? 'active-sheet' : ''}`}
>
{text}
</span>
@@ -22,7 +20,11 @@ const SheetButton = props => {
export default SheetButton;
SheetButton.propTypes = {
name: PropTypes.object,
name: PropTypes.shape({
sheetIndex: PropTypes.number,
text: PropTypes.string,
isActive: PropTypes.bool,
}),
deleteButtonHandler: PropTypes.func,
clickSheetNameHandler: PropTypes.func,
};
+67
View File
@@ -0,0 +1,67 @@
/* eslint-disable no-alert */
import React, { useState, useEffect } from 'react';
import { TransitionGroup, CSSTransition } from 'react-transition-group';
import FormInput from './FormInput';
import SheetButton from './SheetButton';
import server from '../server';
const SheetEditor = () => {
const { getSheetsData, addSheet, deleteSheet, setActiveSheet } = server;
const [names, setNames] = useState([]);
useEffect(() => {
getSheetsData()
.then(setNames)
.catch(alert);
}, []);
const deleteButtonHandler = (e, sheetIndex) => {
deleteSheet(sheetIndex)
.then(setNames)
.catch(alert);
};
const clickSheetNameHandler = (e, sheetName) => {
setActiveSheet(sheetName)
.then(setNames)
.catch(alert);
};
// just for fun, let's use async/await for this one
const newSheetFormHandler = async (e, newSheetTitle) => {
try {
const response = await addSheet(newSheetTitle);
setNames(response);
} catch (error) {
alert(error);
}
};
return (
<div>
<FormInput newSheetFormHandler={newSheetFormHandler} />
<TransitionGroup className="todo-list">
{names.length &&
names.map(name => (
<CSSTransition
transitionName="sheetNames"
transitionAppear={true}
transitionEnterTimeout={300}
transitionLeaveTimeout={300}
key={name.sheetName}
>
<SheetButton
name={name}
deleteButtonHandler={deleteButtonHandler}
clickSheetNameHandler={clickSheetNameHandler}
/>
</CSSTransition>
))}
</TransitionGroup>
</div>
);
};
export default SheetEditor;
-61
View File
@@ -1,61 +0,0 @@
import React, { useState, useEffect } from 'react';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
import FormInput from './form-input';
import SheetButton from './sheet-button';
import server from '../server';
export default function SheetEditor() {
const { getSheetsData, addSheet, deleteSheet, setActiveSheet } = server;
const [names, setNames] = useState([]);
useEffect(() => {
getSheetsData()
.then(setNames)
.catch(alert);
}, []);
const deleteButtonHandler = (e, sheetIndex) => {
deleteSheet(sheetIndex)
.then(setNames)
.catch(alert);
};
const clickSheetNameHandler = (e, sheetName) => {
setActiveSheet(sheetName)
.then(setNames)
.catch(alert);
};
const newSheetFormHandler = (e, newSheetTitle) => {
addSheet(newSheetTitle)
.then(setNames)
.catch(alert);
};
return (
<div>
<FormInput newSheetFormHandler={newSheetFormHandler} />
<ReactCSSTransitionGroup
transitionName="sheetNames"
transitionAppear={true}
transitionEnterTimeout={100}
transitionLeaveTimeout={100}
>
{names.length
? names.map(name => {
return (
<SheetButton
name={name}
deleteButtonHandler={deleteButtonHandler}
clickSheetNameHandler={clickSheetNameHandler}
key={name.sheetName}
/>
);
})
: null}
</ReactCSSTransitionGroup>
</div>
);
}
-10
View File
@@ -1,10 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import SheetEditor from './components/sheet-editor';
import './styles.css';
ReactDOM.render(
<SheetEditor />,
document.getElementById('index')
);
+23 -20
View File
@@ -1,29 +1,32 @@
/*
Convert google script server calls to more
familiar js/promise-based functions.
*/
// Convert google script server calls to more familiar promise-based functions
const serverMethods = {};
const myServerFunctions = {};
// skip the reserved methods
const ignoredMethods = [
// identify the reserved functions
const ignoredMethods = new Set([
'withFailureHandler',
'withLogger',
'withSuccessHandler',
'withUserObject',
];
]);
for (const method in google.script.run) {
if (!ignoredMethods.includes(method)) {
serverMethods[method] = (...args) => {
return new Promise((resolve, reject) => {
google.script.run
.withSuccessHandler(resolve)
.withFailureHandler(reject)[method](...args);
});
};
}
}
// get all the public/global function names from the server
const serverFunctionNames = Object.keys(google.script.run);
// filter out the reserved names
const myServerFunctionNames = serverFunctionNames.filter(
serverFunction => !ignoredMethods.has(serverFunction)
);
export default serverMethods;
// save each function to our new server object using promises
myServerFunctionNames.forEach(serverFunctionName => {
myServerFunctions[serverFunctionName] = (...args) =>
new Promise((resolve, reject) => {
google.script.run
.withSuccessHandler(resolve)
.withFailureHandler(reject)
[serverFunctionName](...args);
});
});
export default myServerFunctions;
+14 -11
View File
@@ -1,14 +1,17 @@
{
"presets": [
["@babel/env", {
"modules": false
}]
],
"plugins": [
"transform-es3-property-literals",
"transform-es3-member-expression-literals",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-object-rest-spread",
"@babel/plugin-transform-object-assign"
"presets": [
[
"@babel/env",
{
"modules": false
}
]
],
"plugins": [
"transform-es3-property-literals",
"transform-es3-member-expression-literals",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-object-rest-spread",
"@babel/plugin-transform-object-assign"
]
}
+7 -9
View File
@@ -1,18 +1,16 @@
{
"root": true,
"parser": "babel-eslint",
"extends": ["airbnb-base", "prettier"],
"plugins": ["googleappsscript", "prettier"],
"extends": ["airbnb-base", "plugin:prettier/recommended"],
"plugins": ["prettier", "googleappsscript"],
"env": {
"googleappsscript/googleappsscript": true
},
"globals": {
"SpreadsheetApp": true,
"HtmlService": true,
"global": true
},
"rules": {
"import/prefer-default-export": 0,
"prettier/prettier": "error"
"prettier/prettier": "error",
"camelcase": "warn",
"import/prefer-default-export": "warn",
"import/no-extraneous-dependencies": "warn",
"prefer-object-spread": "warn"
}
}
-10
View File
@@ -1,10 +0,0 @@
import * as publicFunctions from './sheets-utilities';
// Expose public functions
global.onOpen = publicFunctions.onOpen;
global.openDialog = publicFunctions.openDialog;
global.openAboutSidebar = publicFunctions.openAboutSidebar;
global.getSheetsData = publicFunctions.getSheetsData;
global.addSheet = publicFunctions.addSheet;
global.deleteSheet = publicFunctions.deleteSheet;
global.setActiveSheet = publicFunctions.setActiveSheet;
+11
View File
@@ -0,0 +1,11 @@
import * as publicUiFunctions from './ui';
import * as publicSheetFunctions from './sheets';
// Expose public functions by attaching to `global`
global.onOpen = publicUiFunctions.onOpen;
global.openDialog = publicUiFunctions.openDialog;
global.openAboutSidebar = publicUiFunctions.openAboutSidebar;
global.getSheetsData = publicSheetFunctions.getSheetsData;
global.addSheet = publicSheetFunctions.addSheet;
global.deleteSheet = publicSheetFunctions.deleteSheet;
global.setActiveSheet = publicSheetFunctions.setActiveSheet;
-65
View File
@@ -1,65 +0,0 @@
// Use ES6/7 code
const onOpen = () => {
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.createMenu('Custom scripts')
.addItem('Edit sheets [sample React project]', 'openDialog')
.addItem('About me', 'openAboutSidebar')
.addToUi();
};
const openDialog = () => {
const html = HtmlService.createHtmlOutputFromFile('main')
.setWidth(400)
.setHeight(600);
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.showModalDialog(html, 'Sheet Editor');
};
const openAboutSidebar = () => {
const html = HtmlService.createHtmlOutputFromFile('about');
SpreadsheetApp.getUi().showSidebar(html);
};
const getSheets = () => SpreadsheetApp.getActive().getSheets();
const getActiveSheetName = () => SpreadsheetApp.getActive().getSheetName();
const getSheetsData = () => {
const activeSheetName = getActiveSheetName();
return getSheets().map((sheet, index) => {
const sheetName = sheet.getName();
return {
text: sheetName,
sheetIndex: index,
isActive: sheetName === activeSheetName,
};
});
};
const addSheet = sheetTitle => {
SpreadsheetApp.getActive().insertSheet(sheetTitle);
return getSheetsData();
};
const deleteSheet = sheetIndex => {
const sheets = getSheets();
SpreadsheetApp.getActive().deleteSheet(sheets[sheetIndex]);
return getSheetsData();
};
const setActiveSheet = sheetName => {
SpreadsheetApp.getActive()
.getSheetByName(sheetName)
.activate();
return getSheetsData();
};
export {
onOpen,
openDialog,
openAboutSidebar,
getSheetsData,
addSheet,
deleteSheet,
setActiveSheet,
};
+33
View File
@@ -0,0 +1,33 @@
const getSheets = () => SpreadsheetApp.getActive().getSheets();
const getActiveSheetName = () => SpreadsheetApp.getActive().getSheetName();
export const getSheetsData = () => {
const activeSheetName = getActiveSheetName();
return getSheets().map((sheet, index) => {
const sheetName = sheet.getName();
return {
text: sheetName,
sheetIndex: index,
isActive: sheetName === activeSheetName,
};
});
};
export const addSheet = sheetTitle => {
SpreadsheetApp.getActive().insertSheet(sheetTitle);
return getSheetsData();
};
export const deleteSheet = sheetIndex => {
const sheets = getSheets();
SpreadsheetApp.getActive().deleteSheet(sheets[sheetIndex]);
return getSheetsData();
};
export const setActiveSheet = sheetName => {
SpreadsheetApp.getActive()
.getSheetByName(sheetName)
.activate();
return getSheetsData();
};
+19
View File
@@ -0,0 +1,19 @@
export const onOpen = () => {
SpreadsheetApp.getUi()
.createMenu('My Sample React Project') // edit me!
.addItem('Sheet Name Editor', 'openDialog')
.addItem('About me', 'openAboutSidebar')
.addToUi();
};
export const openDialog = () => {
const html = HtmlService.createHtmlOutputFromFile('main')
.setWidth(400)
.setHeight(600);
SpreadsheetApp.getUi().showModalDialog(html, 'Sheet Editor');
};
export const openAboutSidebar = () => {
const html = HtmlService.createHtmlOutputFromFile('about');
SpreadsheetApp.getUi().showSidebar(html);
};