Compare commits

...
7 Commits
Author SHA1 Message Date
Zaid Abdulla e4582695b7 1.2.5 2021-03-12 15:36:19 -08:00
Zaid Abdulla 0064c2b951 Changelog for v1.2.5 2021-03-12 15:36:05 -08:00
Zaid Abdulla 47c2d6ee6f Update dependencies 2021-03-12 15:30:21 -08:00
Zaid Abdulla f290ce696f Support custom types for uploaded files 2021-03-12 15:30:13 -08:00
Zaid Abdulla 556424d4d6 Fix missing padding at bottom of page in Chrome 2021-03-12 13:08:45 -08:00
Zaid Abdulla 7e507125c4 Remove --unsafe-perm as it's no longer necessary 2021-03-10 16:56:45 -08:00
Zaid Abdulla 2ca0caa258 Reimplement foldString without regex
Lookbehind in regex is not supported in Safari browsers. This implementation
should be more efficient so why not.
2021-02-26 13:22:58 -08:00
12 changed files with 4571 additions and 914 deletions

No files matched your search

+5
View File
@@ -1,5 +1,10 @@
# Change Log # Change Log
## 1.2.5 (2021-03-12)
- Support specifying custom types when uploading files.
- Fix JS compatibility issue with Safari browser.
## 1.2.4 (2021-02-24) ## 1.2.4 (2021-02-24)
- The data model state of a CPE is no longer forgotten after unsuccessful - The data model state of a CPE is no longer forgotten after unsuccessful
+1 -1
View File
@@ -17,7 +17,7 @@ supported versions are:
Install GenieACS from NPM: Install GenieACS from NPM:
sudo npm install -g --unsafe-perm genieacs sudo npm install -g genieacs
To build from source instead, clone this repo or download the source archive To build from source instead, clone this repo or download the source archive
then _cd_ into the source directory then run: then _cd_ into the source directory then run:
+1 -1
View File
@@ -34,7 +34,7 @@ Install GenieACS
.. parsed-literal:: .. parsed-literal::
sudo npm install -g --unsafe-perm genieacs@\ |release| sudo npm install -g genieacs@\ |release|
.. topic:: Installing from source .. topic:: Installing from source
+24 -9
View File
@@ -29,21 +29,36 @@ function stringifyKey(str: string): string {
function foldString(str: string): string[] { function foldString(str: string): string[] {
if (str.length <= LINE_WIDTH) return [str]; if (str.length <= LINE_WIDTH) return [str];
if (str.startsWith(" ")) return [str]; if (str.startsWith(" ")) return [str];
const words = str.split(/(?<=[^ ]) (?=[^ ])/);
const lines: string[] = []; const lines: string[] = [];
let idx = 0; let idx = 0;
let len = 0; let cand = 0;
for (const [i, word] of words.entries()) { for (let i = 1; i < str.length - 1; ++i) {
len += word.length + 1; if (str[i] !== " ") continue;
if (len >= LINE_WIDTH && len !== word.length) {
lines.push(words.slice(idx, i).join(" ")); if (str[i + 1] === " ") {
idx = i; i += 2;
len = 0; while (str[i] === " ") ++i;
continue;
} }
if (i <= idx + LINE_WIDTH) {
cand = i;
continue;
}
const c = cand > idx ? cand : i;
lines.push(str.slice(idx, c));
idx = c + 1;
cand = i;
} }
if (idx < words.length) lines.push(words.slice(idx).join(" ")); if (cand > idx && str.length > idx + LINE_WIDTH) {
lines.push(str.slice(idx, cand));
idx = cand + 1;
}
lines.push(str.slice(idx));
return lines; return lines;
} }
+4442 -884
View File
File diff suppressed because it is too large. Load diff
+12 -12
View File
@@ -1,6 +1,6 @@
{ {
"name": "genieacs", "name": "genieacs",
"version": "1.2.4", "version": "1.2.5",
"description": "A TR-069 Auto Configuration Server (ACS)", "description": "A TR-069 Auto Configuration Server (ACS)",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -41,33 +41,33 @@
"@rollup/plugin-typescript": "^8.2.0", "@rollup/plugin-typescript": "^8.2.0",
"@types/codemirror": "0.0.108", "@types/codemirror": "0.0.108",
"@types/jsonwebtoken": "^8.5.0", "@types/jsonwebtoken": "^8.5.0",
"@types/koa": "^2.13.0", "@types/koa": "^2.13.1",
"@types/koa-compress": "^4.0.1", "@types/koa-compress": "^4.0.1",
"@types/koa-router": "^7.4.1", "@types/koa-router": "^7.4.1",
"@types/koa-static": "^4.0.1", "@types/koa-static": "^4.0.1",
"@types/mithril": "^2.0.6", "@types/mithril": "^2.0.6",
"@types/mongodb": "^3.6.8", "@types/mongodb": "^3.6.9",
"@types/node": "^14.14.31", "@types/node": "^14.14.34",
"@types/parsimmon": "^1.10.6", "@types/parsimmon": "^1.10.6",
"@types/seedrandom": "^2.4.28", "@types/seedrandom": "^3.0.0",
"@typescript-eslint/eslint-plugin": "^4.15.2", "@typescript-eslint/eslint-plugin": "^4.17.0",
"@typescript-eslint/parser": "^4.15.2", "@typescript-eslint/parser": "^4.17.0",
"ava": "^3.15.0", "ava": "^3.15.0",
"codemirror": "^5.59.4", "codemirror": "^5.59.4",
"cssnano": "^4.1.10", "cssnano": "^4.1.10",
"eslint": "^7.20.0", "eslint": "^7.22.0",
"eslint-config-prettier": "^8.1.0", "eslint-config-prettier": "^8.1.0",
"esm": "^3.2.25", "esm": "^3.2.25",
"mithril": "^2.0.4", "mithril": "^2.0.4",
"postcss": "^8.2.6", "postcss": "^8.2.8",
"postcss-import": "^14.0.0", "postcss-import": "^14.0.0",
"postcss-preset-env": "^6.7.0", "postcss-preset-env": "^6.7.0",
"prettier": "^2.2.1", "prettier": "^2.2.1",
"rollup": "^2.39.1", "rollup": "^2.41.2",
"rollup-plugin-terser": "^7.0.2", "rollup-plugin-terser": "^7.0.2",
"svgo": "^2.1.0", "svgo": "^2.2.2",
"ts-node": "^9.1.1", "ts-node": "^9.1.1",
"typescript": "^4.1.5", "typescript": "^4.2.3",
"yaml": "^1.10.0" "yaml": "^1.10.0"
}, },
"engines": { "engines": {
+7
View File
@@ -342,6 +342,13 @@ body {
flex-grow: 1; flex-grow: 1;
margin: 10px; margin: 10px;
min-height: 250px; min-height: 250px;
/* Workaround for Chrome ignoring bottom margin when flex container overflows */
&::after {
content: "";
display: block;
padding-bottom: 1px;
}
} }
table.table { table.table {
+62
View File
@@ -0,0 +1,62 @@
/**
* Copyright 2013-2021 GenieACS Inc.
*
* This file is part of GenieACS.
*
* GenieACS is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* GenieACS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with GenieACS. If not, see <http://www.gnu.org/licenses/>.
*/
import m, { ClosureComponent, Component, Vnode } from "mithril";
const elements: Map<string, Vnode> = new Map();
// Source: https://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
function hash(str: string): number {
let res = 0;
for (let i = 0; i < str.length; ++i) {
const c = str.charCodeAt(i);
res = (res << 5) - res + c;
res |= 0;
}
return res;
}
export function getDatalistId(options: string[]): string {
const id = "datalist" + options.reduce((acc, cur) => acc ^ hash(cur), 0);
if (!elements.has(id)) {
const n = m(
"datalist",
{ id },
options.map((o) => m("option", { value: o }))
);
elements.set(id, n);
}
return id;
}
const component: ClosureComponent = (): Component => {
return {
view: () => {
return [...elements.values()];
},
onupdate: () => {
for (const id of elements.keys()) {
const used = document.querySelector(`[list='${id}']`);
if (!used) elements.delete(id);
}
},
};
};
export default component;
+9 -6
View File
@@ -121,12 +121,15 @@ function renderStagingDownload(task: StageTask): Children {
if (productClass) productClass = decodeURIComponent(productClass); if (productClass) productClass = decodeURIComponent(productClass);
const typesList = [ const typesList = [
"", ...new Set([
"1 Firmware Upgrade Image", "",
"2 Web Content", "1 Firmware Upgrade Image",
"3 Vendor Configuration File", "2 Web Content",
"4 Tone File", "3 Vendor Configuration File",
"5 Ringer File", "4 Tone File",
"5 Ringer File",
...files.value.map((f) => f["metadata.fileType"]).filter((f) => f),
]),
].map((t) => ].map((t) =>
m( m(
"option", "option",
-1
View File
@@ -45,7 +45,6 @@ const attributes: {
{ {
id: "metadata.fileType", id: "metadata.fileType",
label: "Type", label: "Type",
type: "combo",
options: [ options: [
"1 Firmware Upgrade Image", "1 Firmware Upgrade Image",
"2 Web Content", "2 Web Content",
+2
View File
@@ -24,6 +24,7 @@ import userMenu from "./user-menu";
import adminMenu from "./admin-menu"; import adminMenu from "./admin-menu";
import * as overlay from "./overlay"; import * as overlay from "./overlay";
import { version as VERSION } from "../package.json"; import { version as VERSION } from "../package.json";
import datalist from "./datalist";
const adminPages = [ const adminPages = [
"presets", "presets",
@@ -69,6 +70,7 @@ const component: ClosureComponent = (): Component => {
]) ])
), ),
overlay.render(), overlay.render(),
m(datalist),
]; ];
}, },
}; };
+6
View File
@@ -20,6 +20,7 @@
import { VnodeDOM, ClosureComponent, Component, Children } from "mithril"; import { VnodeDOM, ClosureComponent, Component, Children } from "mithril";
import { m } from "./components"; import { m } from "./components";
import codeEditorComponent from "./code-editor-component"; import codeEditorComponent from "./code-editor-component";
import { getDatalistId } from "./datalist";
const singular = { const singular = {
presets: "preset", presets: "preset",
@@ -151,9 +152,14 @@ function createField(current, attr, focus): Children {
}); });
} }
let datalist: string = null;
if (attr.options) datalist = getDatalistId(attr.options);
return m("input", { return m("input", {
type: attr.type === "password" ? "password" : "text", type: attr.type === "password" ? "password" : "text",
name: attr.id, name: attr.id,
list: datalist,
autocomplete: datalist ? "off" : null,
disabled: attr.id === "_id" && !current.isNew, disabled: attr.id === "_id" && !current.isNew,
value: current.object[attr.id], value: current.object[attr.id],
oncreate: focus oncreate: focus