Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bust-cache.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const fs = require('fs');
const { version } = require('./package.json');

let swFile = fs.readFileSync('./service-worker.js', 'utf-8');
swFile = swFile.replace(/LATEST_VERSION = '[^']+';/, `LATEST_VERSION = '${version}';`);
fs.writeFileSync('./service-worker.js', swFile);
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
{
"name": "duinoapp-client",
"version": "3.0.1",
"version": "3.1.0",
"author": "Fraser Bullock",
"license": "GPL-3.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
"lint": "vue-cli-service lint",
"version": "node bust-cache.js && git add package.json service-worker.js"
},
"dependencies": {
"@feathersjs/feathers": "^4.5.8",
Expand All @@ -18,8 +19,11 @@
"debounce-promise": "^3.1.2",
"feathers-localstorage": "^5.1.1",
"feathers-vuex": "^3.12.3",
"fflate": "^0.4.4",
"file-saver": "^2.0.5",
"intel-hex": "^0.1.2",
"lodash": "^4.17.15",
"monaco-editor-webpack-plugin": "<=1.8.2",
"register-service-worker": "^1.7.1",
"roboto-fontface": "*",
"sass": "^1.26.7",
Expand Down
36 changes: 36 additions & 0 deletions service-worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// service-worker.js

workbox.core.setCacheNameDetails({ prefix: 'd4' });

// Do not touch this line
const LATEST_VERSION = '3.1.0';

self.addEventListener('activate', (event) => {
console.log(`%c ${LATEST_VERSION} `, 'background: #ddd; color: #0000ff');
if (caches) {
caches.keys().then((arr) => {
arr.forEach((key) => {
if (key.indexOf('d4-precache') < -1) {
caches.delete(key).then(() => console.log(`%c Cleared ${key}`, 'background: #333; color: #ff0000'));
} else {
caches.open(key).then((cache) => {
cache.match('version').then((res) => {
if (!res) {
cache.put('version', new Response(LATEST_VERSION, { status: 200, statusText: LATEST_VERSION }));
} else if (res.statusText !== LATEST_VERSION) {
caches.delete(key).then(() => console.log(`%c Cleared Cache ${LATEST_VERSION}`, 'background: #333; color: #ff0000'));
} else console.log(`%c Great you have the latest version ${LATEST_VERSION}`, 'background: #333; color: #00ff00');
});
});
}
});
});
}
});

workbox.skipWaiting();
workbox.clientsClaim();

self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
13 changes: 9 additions & 4 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,16 @@ export default {
else setTimeout(() => this.checkSerialReady(), 100);
},
},
mounted() {
async mounted() {
this.checkSerialReady();
this.$FeathersVuex.api.File.find();
this.$FeathersVuex.api.Project.find();
this.$FeathersVuex.api.Setting.find();
this.$FeathersVuex.api.File.find({ query: { $limit: 9999999 } });
this.$FeathersVuex.api.Project.find({ query: { $limit: 9999999 } });
await this.$FeathersVuex.api.Setting.find({ query: { $limit: 9999999 } });
const { Setting } = this.$FeathersVuex.api;
const { data } = Setting.findInStore({ query: { key: 'editor' } });
// eslint-disable-next-line no-console
console.log(data[0]);
this.$vuetify.theme.dark = /(dark)|(black)/.test(data[0]?.value?.theme ?? '');
},
};
</script>
Expand Down
157 changes: 157 additions & 0 deletions src/components/files/add-file.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<template>
<v-dialog v-model="dialog" max-width="500px">
<template #activator="{ on }">
<slot name="activator" :on="on" />
</template>
<v-card>
<v-card-title>
Add File
</v-card-title>
<v-card-text>
<v-row>
<v-col cols="12">
<v-select
v-model="location"
:items="items"
label="Location"
outlined
/>
</v-col>
<v-col cols="12" sm="9">
<v-text-field
v-model.trim="name"
:error-messages="nameError"
label="Name"
outlined
/>
</v-col>
<v-col cols="12" sm="3">
<v-select
v-model="ext"
:items="['.c', '.cpp', '.h', '.ino', '.md', '.txt']"
label="Type"
outlined
/>
</v-col>
<v-col cols="12" class="text-caption" v-if="!!name">
{{project.ref}}/{{location}}{{name}}{{ext}}
</v-col>
</v-row>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn text @click="dialog = false">
Cancel
</v-btn>
<v-btn :disabled="!name || !!nameError" depressed color="primary" @click="add">
Add File
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>

<script>
import { mapGetters } from 'vuex';
import set from 'lodash/set';

export default {
props: {
project: {
type: Object,
default: () => ({}),
},
path: {
type: String,
default: '',
},
},
data() {
return {
dialog: false,
name: '',
location: '',
ext: '.c',
};
},
computed: {
...mapGetters('files', { findFiles: 'find' }),
nameError() {
if (/[^\w-.]/.test(this.name)) return 'File name can only contain a-z, A-Z, 0-9, ., - or _ characters.';
return '';
},
items() {
if (!this.project?.ref) return [];
const files = this.findFiles({
query: { projectId: this.project.uuid },
}).data;
const filesObject = files.reduce((a, file) => set(a, file.name.replace(/\./g, '').replace(/\//g, '.'), file), {});
const processObject = (obj, parent) => Object.keys(obj).reduce((a, i) => {
if (obj[i]._id) return a;
const text = `${parent}${i}/`;
return [...a, { text, value: text.replace(`${this.project.ref}/`, '') }, ...processObject(obj[i], text)];
}, []);
const foldersArray = [{ text: `${this.project.ref}/`, value: '' }, ...processObject(filesObject, `${this.project.ref}/`)];
return foldersArray;
},
fileType() {
switch (this.ext) {
case '.ino':
return 'text/x-arduino';
case '.c':
case '.cpp':
case '.h':
return 'text/x-c';
case '.md':
return 'text/markdown';
default:
return 'text/plain';
}
},
},
methods: {
async add() {
if (!this.name || this.nameError) return;
const { File } = this.$FeathersVuex.api;
const file = new File({
name: `${this.location}${this.name}${this.ext}`,
ref: `${this.project.ref}/${this.location}${this.name}${this.ext}`,
body: '',
contentType: this.fileType,
main: false,
projectId: this.project.uuid,
});
await file.save();
this.$store.commit('setCurrentFile', file.uuid);
this.name = '';
this.dialog = false;
},
},
mounted() {
if (this.project.ref) this.location = this.path.replace(`${this.project.ref}/`, '');
},
watch: {
'project.ref': {
handler(to, from) {
if (!to || to === from) return;
this.location = this.path.replace(`${this.project.ref}/`, '');
if (!this.items.some((item) => item.value === this.location)) this.location = '';
},
},
path(to, from) {
if (!to || to === from) return;
this.location = this.path.replace(`${this.project.ref}/`, '');
if (!this.items.some((item) => item.value === this.location)) this.location = '';
},
dialog(to, from) {
if (to === from) return;
if (to) this.$emit('open');
else this.$emit('close');
},
},
};
</script>

<style>

</style>
133 changes: 133 additions & 0 deletions src/components/files/add-folder.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<template>
<v-dialog v-model="dialog" max-width="500px">
<template #activator="{ on }">
<slot name="activator" :on="on" />
</template>
<v-card>
<v-card-title>
Add Folder
</v-card-title>
<v-card-text>
<v-row>
<v-col cols="12">
<v-select
v-model="location"
:items="items"
label="Location"
outlined
/>
</v-col>
<v-col cols="12">
<v-text-field
v-model.trim="name"
:error-messages="nameError"
label="Name"
outlined
/>
</v-col>
<v-col cols="12" class="text-caption" v-if="!!name">
{{project.ref}}/{{location}}{{name}}/
</v-col>
</v-row>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn text @click="dialog = false">
Cancel
</v-btn>
<v-btn :disabled="!name || !!nameError" depressed color="primary" @click="add">
Add Folder
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>

<script>
import { mapGetters } from 'vuex';
import set from 'lodash/set';

export default {
props: {
project: {
type: Object,
default: () => ({}),
},
path: {
type: String,
default: '',
},
},
data() {
return {
dialog: false,
name: '',
location: '',
};
},
computed: {
...mapGetters('files', { findFiles: 'find' }),
nameError() {
if (/[^\w-]/.test(this.name)) return 'Folder name can only contain a-z, A-Z, 0-9, - or _ characters.';
return '';
},
items() {
if (!this.project?.ref) return [];
const files = this.findFiles({
query: { projectId: this.project.uuid },
}).data;
const filesObject = files.reduce((a, file) => set(a, file.name.replace(/\./g, '').replace(/\//g, '.'), file), {});
const processObject = (obj, parent) => Object.keys(obj).reduce((a, i) => {
if (obj[i]._id) return a;
const text = `${parent}${i}/`;
return [...a, { text, value: text.replace(`${this.project.ref}/`, '') }, ...processObject(obj[i], text)];
}, []);
const foldersArray = [{ text: `${this.project.ref}/`, value: '' }, ...processObject(filesObject, `${this.project.ref}/`)];
return foldersArray;
},
},
methods: {
async add() {
if (!this.name || this.nameError) return;
const { File } = this.$FeathersVuex.api;
const file = new File({
name: `${this.location}${this.name}/.gitkeep`,
ref: `${this.project.ref}/${this.location}${this.name}/.gitkeep`,
body: '',
contentType: 'text/plain',
main: false,
projectId: this.project.uuid,
});
await file.save();
this.name = '';
this.dialog = false;
},
},
mounted() {
if (this.project.ref) this.location = this.path.replace(`${this.project.ref}/`, '');
},
watch: {
'project.ref': {
handler(to, from) {
if (!to || to === from) return;
this.location = this.path.replace(`${this.project.ref}/`, '');
if (!this.items.some((item) => item.value === this.location)) this.location = '';
},
},
path(to, from) {
if (!to || to === from) return;
this.location = this.path.replace(`${this.project.ref}/`, '');
if (!this.items.some((item) => item.value === this.location)) this.location = '';
},
dialog(to, from) {
if (to === from) return;
if (to) this.$emit('open');
else this.$emit('close');
},
},
};
</script>

<style>

</style>
Loading