Wifi UI update

This commit is contained in:
Sebastien
2020-12-21 11:01:22 -05:00
parent 2d573da503
commit 7c13c130b8
81 changed files with 5032 additions and 4697 deletions

View File

@@ -0,0 +1,9 @@
module.exports = {
parser: 'sugarss',
// syntax: 'postcss-scss',
plugins: {
'postcss-import': {},
'postcss-cssnext': {},
cssnano: {}
}
}

View File

@@ -0,0 +1,231 @@
/* eslint-disable */
// Common Config is used in Development and Production Mode.
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
const StylelintPlugin = require('stylelint-webpack-plugin');
const ESLintPlugin = require('eslint-webpack-plugin');
const SpriteLoaderPlugin = require('svg-sprite-loader/plugin');
// Linting
const TSLintPlugin = require('tslint-webpack-plugin');
module.exports = {
entry: {
index: './src/index.ts'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: './js/[name].[hash:6].bundle.js'
},
module: {
rules: [
// Raw Loader
{
test: /\.txt$/,
use: 'raw-loader'
},
// HTML Loader
{
test: /\.html$/,
use: [
{
loader: 'html-loader',
options: {minimize: true}
}
]
},
// CSS/SCSS Loader & Minimizer
{
test: /\.(sa|sc|c)ss$/,
use: [
"style-loader",
"css-loader",
{
loader: 'postcss-loader',
options: {
postcssOptions: {
parser: "sugarss",
},
},
},
{
loader: 'resolve-url-loader',
options: {}
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
sourceMapContents: false
}
}
],
},
{
test: /\.svg$/,
use: [
{
loader: 'svg-sprite-loader',
options: {
extract: true,
} },
'svg-transform-loader',
{
loader: 'svgo-loader',
options: {
plugins: [
{removeTitle: true},
{convertColors: {shorthex: false}},
{convertPathData: false},
{convertPathData:true}
]
}
}
]
},
// Image Loader
{
test: /\.(png|jpeg|jpg|webp|gif|ico)/i,
use: [
{
loader: 'url-loader',
options: {
// publicPath: '../',
name: './assets/images/' + '[name].[ext]',
limit: 10000,
publicPath: '../'
}
},
]
},
// Babel Loader
{
test: /\.ts(x?)$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-proposal-nullish-coalescing-operator',
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-proposal-class-properties'
]
}
},
},
// XML Loader
{
test: /\.xml$/,
use: [
'xml-loader'
]
},
{
test: require.resolve("bootstrap"),
loader: "expose-loader",
options: {
exposes: ["bootstrap"],
},
},
{
test: require.resolve("jquery"),
loader: "expose-loader",
options: {
exposes: ["$", "jQuery"],
},
},
{
test: require.resolve("underscore"),
loader: "expose-loader",
options: {
exposes: [
"_.map|map",
{
globalName: "_.reduce",
moduleLocalName: "reduce",
},
{
globalName: ["_", "filter"],
moduleLocalName: "filter",
},
],
},
},
]
},
resolve: {
extensions: ['.js', '.jsx', '.tsx', '.ts', '.json'],
alias: {
riSvg: 'remixicon/icons/'
}
},
plugins: [
new CleanWebpackPlugin(),
new ESLintPlugin({
cache: true,
ignore: true,
useEslintrc: true,
}),
new HtmlWebPackPlugin({
title: 'SqueezeESP32',
template: './src/index.ejs',
filename: 'index.html',
inject: 'body',
minify: {
html5 : true,
collapseWhitespace : true,
minifyCSS : true,
minifyJS : true,
minifyURLs : false,
removeAttributeQuotes : true,
removeComments : true, // false for Vue SSR to find app placeholder
removeEmptyAttributes : true,
removeOptionalTags : true,
removeRedundantAttributes : true,
removeScriptTypeAttributes : true,
removeStyleLinkTypeAttributese : true,
useShortDoctype : true
},
favicon: "./src/assets/images/favicon-32x32.png",
excludeChunks: ['test'],
}),
new ScriptExtHtmlWebpackPlugin({
defaultAttribute: 'defer'
}),
// // Load Lodash Features Separately https://www.npmjs.com/package/lodash-webpack-plugin
new LodashModuleReplacementPlugin({
'collections': true,
'paths': true,
}),
new TSLintPlugin({
files: ['./src/ts/*.ts']
}),
new StylelintPlugin( {
files: ['./src/sass/*.s?(a|c)ss'],
configFile: './config/.stylelintrc',
emitError: true,
emitWarning: true,
failOnError: false,
fix: true
}),
new SpriteLoaderPlugin({plainSprite: true})
],
};

View File

@@ -0,0 +1,235 @@
/* eslint-disable */
var path = require('path');
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const bodyParser = require('body-parser')
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { config } = require('process');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const SpriteLoaderPlugin = require('svg-sprite-loader/plugin');
const { Command } = require('commander');
let cmdLines= { };
const data = {
messages: require("../mock/messages.json"),
messagequeue: require("../mock/messages.json"),
commands: require("../mock/commands.json"),
scan: require("../mock/scan.json"),
ap: require("../mock/ap.json"),
config: require("../mock/config.json"),
statusdefinition: require("../mock/statusdefinition.json"),
status: require("../mock/status.json")
};
const messagingTypes= {
MESSAGING_INFO : 'MESSAGING_INFO',
MESSAGING_WARNING : 'MESSAGING_WARNING',
MESSAGING_ERROR : 'MESSAGING_ERROR'
};
const messagingClass= {
MESSAGING_CLASS_OTA : 'MESSAGING_CLASS_OTA',
MESSAGING_CLASS_SYSTEM : 'MESSAGING_CLASS_SYSTEM',
MESSAGING_CLASS_STATS : 'MESSAGING_CLASS_STATS',
MESSAGING_CLASS_CFGCMD: 'MESSAGING_CLASS_CFGCMD',
MESSAGING_CLASS_BT: 'MESSAGING_CLASS_BT'
} ;
function requeueMessages(){
data.messagequeue.push(...data.messages);
console.log(`Re-queued ${data.messages.length} messages. Total queue length is: ${data.messagequeue.length}`);
}
function sendMessaging(cmdname,msgtype,msgClass,msg){
let message_txt=`${cmdname}\n${msg}`;
var d = new Date();
var n = d.getMilliseconds();
data.messagequeue.push({
message: message_txt,
type: msgtype,
class: msgClass,
sent_time: n,
current_time: n});
console.log(`Queued message ~${data.messagequeue.length} type ${msgtype}, class ${msgClass}: ${message_txt}`);
}
Array.prototype.filter = function(fun /*, thisp*/) {
var len = this.length >>> 0;
if (typeof fun != "function")
throw new TypeError();
var res = [];
var thisp = arguments[1];
for (var i = 0; i < len; i++) {
if (i in this) {
var val = this[i];
if (fun.call(thisp, val, i, this))
res.push(val);
}
}
return res;
};
for(const cmdIdx in data.commands.commands){
const cmd = data.commands.commands[cmdIdx];
//console.log(`Creating command structure for ${cmd.name}`);
cmdLines[cmd.name] = {
cmd: new Command(),
};
cmdLines[cmd.name].cmd
.storeOptionsAsProperties(false)
.name(cmd.name)
.exitOverride();
for(const argIdx in cmd.argtable){
const arg=cmd.argtable[argIdx];
const optstr=((arg.shortopts?'-'+arg.shortopts:'')+
(arg.shortopts && arg.longopts?', ':'')+
(arg.longopts?'--'+arg.longopts:'') +
(arg.hasvalue?`${(arg.shortopts || arg.longopts?' ':'')}<${arg.datatype.replace(/[<>]/gm,'')}>`:''));
//console.log(` Option: ${optstr}, Glossary: ${arg.glossary}`);
if(arg.mincount>0){
cmdLines[cmd.name].cmd.requiredOption( optstr,arg.glossary);
}
else {
cmdLines[cmd.name].cmd.option( optstr,arg.glossary);
}
}
}
const connectReturnCode = {
UPDATE_CONNECTION_OK : 0,
UPDATE_FAILED_ATTEMPT : 1,
UPDATE_USER_DISCONNECT : 2,
UPDATE_LOST_CONNECTION : 3,
UPDATE_FAILED_ATTEMPT_AND_RESTORE : 4
}
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
entry: {
test: './src/test.ts'
},
devServer: {
contentBase: path.join(__dirname, 'dist'),
publicPath: '/',
port: 9100,
host: 'desktop-n8u8515',//your ip address
disableHostCheck: true,
overlay: true,
before: function(app) {
app.use(bodyParser.json()) // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })) // for parsing application/x-www-form-urlencoded
app.get('/ap.json', function(req, res) { res.json( data.ap ); });
app.get('/scan.json', function(req, res) { res.json( data.scan ); });
app.get('/config.json', function(req, res) { res.json( data.config ); });
app.get('/status.json', function(req, res) { res.json( data.status ); });
app.get('/messages.json', function(req, res) {
res.json( data.messagequeue ) ;
data.messagequeue=[];
});
app.get('/statusdefinition.json', function(req, res) { res.json( data.statusdefinition ); });
app.get('/commands.json', function(req, res) { res.json( data.commands ); });
app.post('/commands.json', function(req, res) {
console.log(req.body.command);
try {
const cmdName=req.body.command.split(" ")[0];
const args=('node '+req.body.command).split(" ");
let cmd=cmdLines[cmdName].cmd;
if(cmd){
cmd.parse(args);
const msg=`Received Options: ${JSON.stringify(cmd.opts())}\n`;
console.log('Options: ', cmd.opts());
console.log('Remaining arguments: ', cmd.args);
sendMessaging(cmdName,messagingTypes.MESSAGING_INFO,messagingClass.MESSAGING_CLASS_CFGCMD,msg);
}
} catch (error) {
console.error(error);
}
res.json( { 'Result' : 'Success' } );
});
app.post('/config.json', function(req, res) {
console.log(req.body);
console.log(data.config);
for (const property in req.body.config) {
console.log(`${property}: ${req.body.config[property].value}`);
if(data.config[property]=== undefined){
console.log(`Added config value ${property} [${req.body.config[property].value}]`);
data.config[property] = {value: req.body.config[property].value};
}
else if (data.config[property].value!=req.body.config[property].value){
console.log(`Updated config value ${property}\nFrom: ${data.config[property].value}\nTo: ${req.body.config[property].value}]`);
data.config[property].value=req.body.config[property].value;
}
}
res.json( {} );
});
app.post('/status.json', function(req, res) {
for (const property in req.body.status) {
if(data.status[property]=== undefined){
console.log(`Added status value ${property} [${req.body.status[property]}]`);
data.status[property] = {value: req.body.status[property]};
}
else if (data.status[property]!==req.body.status[property]){
console.log(`Updated status value ${property}\nFrom: ${data.status[property]}\nTo: ${req.body.status[property]}`);
data.status[property]=req.body.status[property];
}
}
res.json( {} );
});
app.post('/connect.json', function(req, res) {
setTimeout(function(r){
if(r.body.ssid.search('fail')>=0){
if(data.status.ssid){
// in this case, the same ssid will be reused - the ESP32 would restore its previous state on failure
data.status.urc=connectReturnCode.UPDATE_FAILED_ATTEMPT_AND_RESTORE;
}
else {
data.status.urc=connectReturnCode.UPDATE_FAILED_ATTEMPT;
}
}
else {
data.status.ssid=r.body.ssid;
data.status.urc=connectReturnCode.UPDATE_CONNECTION_OK;
}
}, 1000, req);
res.json( {} );
});
app.post('/reboot_ota.json', function(req, res) {
data.status.recovery=0;
requeueMessages();
res.json( {} );
});
app.post('/reboot.json', function(req, res) {
res.json( {} );
requeueMessages();
});
app.post('/recovery.json', function(req, res) {
data.status.recovery=1;
requeueMessages();
res.json( { } );
});
app.post('/flash.json', function(req, res) {
if(data.status.recovery>0){
res.json({});
}
else {
res.status(404).end();
}
});
app.delete('/connect.json', function(req, res) {
data.status.ssid='';
res.json( {} ); });
app.get('/reboot', function(req, res) { res.json( {} ); });
},
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].css',
chunkFilename: 'css/[id].css' ,
}),
new HtmlWebPackPlugin({
title: 'SqueezeESP32-test',
template: './src/test.ejs',
filename: 'test',
minify: false,
excludeChunks: ['index'],
}),
new SpriteLoaderPlugin({plainSprite: true})
],
});

View File

@@ -0,0 +1,182 @@
/* eslint-disable */
// Merges webpack.common config with this production config
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
// Optimisations and Compression
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const ImageminPlugin = require('imagemin-webpack-plugin').default;
const imageminMozjpeg = require('imagemin-mozjpeg');
const fs = require('fs');
const glob = require('glob');
var WebpackOnBuildPlugin = require('on-build-webpack');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const path = require('path')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const PurgecssPlugin = require('purgecss-webpack-plugin')
// Optional
const FaviconsWebpackPlugin = require('favicons-webpack-plugin');
const PATHS = {
src: path.join(__dirname, 'src')
}
module.exports = merge(common, {
mode: 'production',
stats: 'errors-only',
optimization: {
minimizer: [
new TerserPlugin({
test: /\.js(\?.*)?$/i,
exclude: /node_modules/,
cache: true,
parallel: 4,
sourceMap: true,
}),
new OptimizeCSSAssetsPlugin({})
],
runtimeChunk: 'single',
splitChunks: {
chunks: 'all',
// maxInitialRequests: Infinity,
// minSize: 0,
cacheGroups: {
vendor: {
test: /node_modules/, // you may add "vendor.js" here if you want to
name: "node-modules",
chunks: "initial",
enforce: true
},
}
},
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].[hash:6].css',
chunkFilename: 'css/[name].[contenthash].css',
}),
new ExtractTextPlugin('[name].css?[hash]'),
new PurgecssPlugin({
paths: glob.sync(`${PATHS.src}/*`),
whitelist: ['whitelisted']
}),
new CleanWebpackPlugin(),
new CompressionPlugin({
test: /\.(js|css|html|svg)$/,
filename: '[path].br[query]',
algorithm: 'brotliCompress',
compressionOptions: { level: 11 },
threshold: 100,
minRatio: 0.8,
deleteOriginalAssets: false
}),
new CompressionPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: /\.js$|\.css$|\.html$/,
threshold: 100,
minRatio: 0.8,
}),
new ImageminPlugin({
test: /\.(jpe?g|png|gif|svg)$/i,
// lossLess gif compressor
gifsicle: {
optimizationLevel: 9
},
// lossy png compressor, remove for default lossLess
pngquant: ({
quality: '75'
}),
// lossy jpg compressor
plugins: [imageminMozjpeg({
quality: '75'
})]
}),
// new FaviconsWebpackPlugin({
// // Your source logo
// logo: './src/assets/images/200px-ControllerAppIcon.png',
// // // The prefix for all image files (might be a folder or a name)
// //prefix: 'assets/icons_[hash:6]/',
// prefix: 'icons_[hash:6]/',
// // // Emit all stats of the generated icons
// //emitStats: false,
// // // The name of the json containing all favicon information
// // statsFilename: 'iconstats-[hash].json',
// // // Generate a cache file with control hashes and
// // // don't rebuild the favicons until those hashes change
// persistentCache: true,
// // // Inject the html into the html-webpack-plugin
// inject: true,
// // // favicon background color (see https://github.com/haydenbleasel/favicons#usage)
// background: '#fff',
// // // which icons should be generated (see https://github.com/haydenbleasel/favicons#usage)
// icons: {
// // android: false,
// // appleIcon: false,
// favicons: true
// // firefox: true,
// // windows: false
// }
// }),
new WebpackOnBuildPlugin(function(stats) {
var getDirectories = function (src, callback) {
glob(`${src}/**/*(*.gz|favicon-32x32.png)`, callback);
};
getDirectories('./webpack/dist', function (err, list) {
if (err) {
console.log('Error', err);
} else {
const regex = /^(.*\/)([^\/]*)$/
const relativeRegex = /(\w+\/[^\/]*)$/
const makePathRegex = /([^\.].*)$/
let exportDefHead=
'/***********************************\n'+
'webpack_headers\n'+
stats+'\n'+
'***********************************/\n'+
'#pragma once\n'+
'#include <inttypes.h>\n'+
'extern const char * resource_lookups[];\n'+
'extern const uint8_t * resource_map_start[];\n'+
'extern const uint8_t * resource_map_end[];\n';
let exportDef= '// Automatically generated. Do not edit manually!.\n'+
'#include <inttypes.h>\n';
let lookupDef='const char * resource_lookups[] = {\n';
let lookupMapStart='const uint8_t * resource_map_start[] = {\n';
let lookupMapEnd='const uint8_t * resource_map_end[] = {\n';
let cMake='';
list.forEach(fileName=>{
let exportName=fileName.match(regex)[2].replace(/[\. \-]/gm,'_');
let relativeName=fileName.match(relativeRegex)[1];
exportDef+= 'extern const uint8_t _'+exportName+'_start[] asm("_binary_'+exportName+'_start");\n'+
'extern const uint8_t _'+exportName+'_end[] asm("_binary_'+exportName+'_end");\n';
lookupDef+='\t"/'+relativeName+'",\n';
lookupMapStart+='\t_'+ exportName+'_start,\n';
lookupMapEnd+= '\t_'+ exportName+'_end,\n';
cMake+='target_add_binary_data( __idf_wifi-manager ./webapp'+fileName.match(makePathRegex)[1]+' BINARY)\n';
});
lookupDef+='""\n};\n';
lookupMapStart=lookupMapStart.substring(0,lookupMapStart.length-2)+'\n};\n';
lookupMapEnd=lookupMapEnd.substring(0,lookupMapEnd.length-2)+'\n};\n';
try {
fs.writeFileSync('webapp.cmake', cMake);
fs.writeFileSync('webpack.c', exportDef+lookupDef+lookupMapStart+lookupMapEnd);
fs.writeFileSync('webpack.h', exportDefHead);
//file written successfully
} catch (e) {
console.error(e);
}
}
});
}),
new BundleAnalyzerPlugin()
]
});