Updated smart form
This commit is contained in:
parent
92607260d1
commit
78eb4050ae
4 changed files with 109 additions and 62 deletions
43
notarize.js
43
notarize.js
|
|
@ -2,8 +2,9 @@ const exec = require('child_process').exec;
|
||||||
const sign = require("electron-osx-sign").signAsync;
|
const sign = require("electron-osx-sign").signAsync;
|
||||||
const notarize = require("electron-notarize").notarize;
|
const notarize = require("electron-notarize").notarize;
|
||||||
|
|
||||||
const app = "Crimata.app";
|
const name = "Crimata";
|
||||||
const dir = `${app}/Contents/Resources/app`;
|
const dir = `${name}.app/Contents/Resources/app`;
|
||||||
|
const registry = "https://gitlab.com/api/v4/projects/25637892/packages/generic/crimata/0.0.1/Crimata.zip";
|
||||||
|
|
||||||
const runShellCommand = (cmd) => (new Promise((resolve, reject) => {
|
const runShellCommand = (cmd) => (new Promise((resolve, reject) => {
|
||||||
exec(cmd, (error, stdout, stderr) => {
|
exec(cmd, (error, stdout, stderr) => {
|
||||||
|
|
@ -11,8 +12,11 @@ const runShellCommand = (cmd) => (new Promise((resolve, reject) => {
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// /projects/:id/packages/generic/:package_name/:package_version/:file_name?status=:status
|
||||||
|
|
||||||
|
|
||||||
const signConfig = {
|
const signConfig = {
|
||||||
"app": app,
|
"app": name + ".app",
|
||||||
"hardened-runtime": true,
|
"hardened-runtime": true,
|
||||||
"gatekeeper-assess": false,
|
"gatekeeper-assess": false,
|
||||||
"signature-flags": "library",
|
"signature-flags": "library",
|
||||||
|
|
@ -21,7 +25,7 @@ const signConfig = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const notarizeConfig = {
|
const notarizeConfig = {
|
||||||
appPath: app,
|
appPath: name + ".app",
|
||||||
appleId: "gundersena@crimata.com",
|
appleId: "gundersena@crimata.com",
|
||||||
appBundleId: "com.crimata.CrimataMessenger",
|
appBundleId: "com.crimata.CrimataMessenger",
|
||||||
appleIdPassword: process.env["AC_PASSWORD"]
|
appleIdPassword: process.env["AC_PASSWORD"]
|
||||||
|
|
@ -31,18 +35,24 @@ const notarizeConfig = {
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
console.log("Building...");
|
// console.log("Building...");
|
||||||
await runShellCommand(`rm -rf ${dir} && mkdir ${dir} && cp -r {package.json,src,node_modules} ${dir}
|
// await runShellCommand(`rm -rf ${dir} && mkdir ${dir} && cp -r {package.json,src,node_modules} ${dir}
|
||||||
`);
|
// `);
|
||||||
|
|
||||||
console.log("Cleaning...");
|
// console.log("Cleaning...");
|
||||||
await runShellCommand(`xattr -cr ${app}`);
|
// await runShellCommand(`xattr -cr ${name}.app`);
|
||||||
|
|
||||||
console.log("Signing...");
|
// console.log("Signing...");
|
||||||
await sign(signConfig);
|
// await sign(signConfig);
|
||||||
|
|
||||||
console.log("Notarizing...");
|
// console.log("Notarizing...");
|
||||||
await notarize(notarizeConfig);
|
// await notarize(notarizeConfig);
|
||||||
|
|
||||||
|
// console.log("Compressing...");
|
||||||
|
// await runShellCommand(`zip -vr ${name}.zip ${name}.app`);
|
||||||
|
|
||||||
|
console.log("Uploading to Gitlab...");
|
||||||
|
await runShellCommand(`curl --header "PRIVATE-TOKEN: ${process.env["API_TOKEN"]}" --upload-file ${name}.zip "${registry}"`);
|
||||||
}
|
}
|
||||||
catch (e)
|
catch (e)
|
||||||
{
|
{
|
||||||
|
|
@ -50,3 +60,10 @@ const notarizeConfig = {
|
||||||
}
|
}
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy file from local to remote:
|
||||||
|
*
|
||||||
|
* scp -r Electron.app gundersena@crimata-server:~/Desktop/crimata/website/assets
|
||||||
|
*/
|
||||||
23
src/render/components/control/valid.js
Normal file
23
src/render/components/control/valid.js
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
export const isEmail = (value) => {
|
||||||
|
console.log(value);
|
||||||
|
if (!/(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/.test(value)) {
|
||||||
|
return "Not a valid email."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isPassword = (value) => {
|
||||||
|
if (!/^(?=.*[0-9])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{6,16}$/.test(value)) {
|
||||||
|
return "Password must have symbol, number, uppercase and be 6-16 length.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name is optional and therefore doesn't return error if no value.
|
||||||
|
*/
|
||||||
|
export const isName = (value) => {
|
||||||
|
if (value) {
|
||||||
|
if (!/^([a-zA-Z ]){5,30}$/.test(value)) {
|
||||||
|
return "Name must be at least 5 long.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,83 +1,86 @@
|
||||||
|
|
||||||
|
// Basic debounce implentation
|
||||||
const debounce = (fn, delay) => {
|
const debounce = (fn, delay) => {
|
||||||
|
|
||||||
let timeoutId;
|
let timeoutId;
|
||||||
|
return (...args) => {
|
||||||
const wrapper = (...args) => {
|
if (timeoutId) clearTimeout(timeoutId);
|
||||||
|
|
||||||
if (timeoutId) {
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
}
|
|
||||||
|
|
||||||
timeoutId = setTimeout(() => {
|
timeoutId = setTimeout(() => {
|
||||||
fn(...args);
|
fn(...args);
|
||||||
}, delay);
|
}, delay);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return wrapper;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dynamic form component with auto submission and validation.
|
||||||
const SmartForm =
|
*
|
||||||
|
* props
|
||||||
|
* .fields => List of field objects
|
||||||
|
* .channel => e.g. "/login"
|
||||||
|
* .modifier => Form description
|
||||||
|
*/
|
||||||
|
const SmartForm =
|
||||||
{
|
{
|
||||||
props: ["fields", "channel", "modifier"],
|
props: ["fields", "channel", "modifier"],
|
||||||
|
|
||||||
setup(props)
|
setup(props)
|
||||||
{
|
{
|
||||||
let logsEl;
|
// Error log below form
|
||||||
|
const log = Vue.ref(props.modifier);
|
||||||
|
|
||||||
const submit = debounce(async (data) => {
|
/**
|
||||||
|
* Valid and submit form data to channel.
|
||||||
|
*/
|
||||||
|
const submit = async () => {
|
||||||
|
|
||||||
let object = {};
|
// Validate each field
|
||||||
data.forEach(function(value, key){
|
for (let field of props.fields) {
|
||||||
object[key] = value;
|
const error = field.valid(field.value);
|
||||||
});
|
if (error) return error;
|
||||||
|
|
||||||
const err = await window.mainApi.invoke(props.channel, object)
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
logsEl.innerText = err;
|
|
||||||
logsEl.style.color = "red";
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logsEl.style.color = "green";
|
// Reduce fields into the form
|
||||||
logsEl.innerText = props.modifier;
|
const form = props.fields.reduce((v, n) => {
|
||||||
|
v[n.name] = n.value;
|
||||||
|
return v;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
console.log("Submitting =>", form);
|
||||||
|
return await window.mainApi.invoke(props.channel, form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for submit that is debounced and updates UI elements
|
||||||
|
*/
|
||||||
|
const preSub = debounce(async () => {
|
||||||
|
|
||||||
|
const error = await submit();
|
||||||
|
|
||||||
|
log.value = error ? error : props.modifier
|
||||||
|
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
|
||||||
Vue.onMounted(() => {
|
return { preSub, log };
|
||||||
|
|
||||||
const el = document.getElementById("smart-form");
|
|
||||||
|
|
||||||
logsEl = el.querySelector(".smart-form-logs");
|
|
||||||
|
|
||||||
logsEl.innerText = props.modifier;
|
|
||||||
|
|
||||||
el.addEventListener("input", () => {
|
|
||||||
submit(new FormData(el))
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
template: `
|
template: `
|
||||||
<form id="smart-form" class="smart-form">
|
<form id="smart-form" class="smart-form" v-on:input="preSub">
|
||||||
|
|
||||||
<div v-for="field in fields" style="display:flex">
|
<div v-for="field in fields" style="display:flex">
|
||||||
|
|
||||||
<input type="text" class="text-field"
|
<input type="text" class="text-field"
|
||||||
|
v-model="field.value"
|
||||||
:name="field.name"
|
:name="field.name"
|
||||||
:value="field.value"
|
|
||||||
:placeholder="field.placeholder"
|
:placeholder="field.placeholder"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="smart-form-logs"></div>
|
<div class="smart-form-logs">{{ log }}</div>
|
||||||
|
|
||||||
</form>`
|
</form>`
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SmartForm;
|
export default SmartForm;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import SmartForm from "./form.js";
|
import SmartForm from "./form.js";
|
||||||
|
import { isEmail, isPassword, isName } from "./control/valid.js";
|
||||||
|
|
||||||
const Login =
|
const Login =
|
||||||
{
|
{
|
||||||
|
|
@ -8,7 +9,7 @@ const Login =
|
||||||
|
|
||||||
setup()
|
setup()
|
||||||
{
|
{
|
||||||
return;
|
return { isEmail, isPassword, isName };
|
||||||
},
|
},
|
||||||
|
|
||||||
template: `
|
template: `
|
||||||
|
|
@ -19,16 +20,19 @@ const Login =
|
||||||
name: 'email',
|
name: 'email',
|
||||||
value: null,
|
value: null,
|
||||||
placeholder: 'Email',
|
placeholder: 'Email',
|
||||||
|
valid: isEmail
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'password',
|
name: 'password',
|
||||||
value: null,
|
value: null,
|
||||||
placeholder: 'Password'
|
placeholder: 'Password',
|
||||||
|
valid: isPassword
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'name',
|
name: 'name',
|
||||||
value: null,
|
value: null,
|
||||||
placeholder: 'Name'
|
placeholder: 'Name',
|
||||||
|
valid: isName
|
||||||
}]"
|
}]"
|
||||||
:channel="'auth'"
|
:channel="'auth'"
|
||||||
:modifier="'Login or enter name to register.'"
|
:modifier="'Login or enter name to register.'"
|
||||||
|
|
@ -37,4 +41,4 @@ const Login =
|
||||||
</div>`
|
</div>`
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Login;
|
export default Login;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue