Skip to content

Commit c97f0bd

Browse files
committed
Repo init
0 parents  commit c97f0bd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+22043
-0
lines changed

.editorconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
indent_style = space
6+
indent_size = 2
7+
end_of_line = lf
8+
insert_final_newline = true
9+
trim_trailing_whitespace = true
10+
11+
[*.md]
12+
trim_trailing_whitespace = false

.env.example

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Server configuration
2+
HOSTNAME=
3+
PORT=3000
4+
IP=0.0.0.0
5+
HISTORY_API_FALLBACK=
6+
7+
# Auth configuration
8+
AUTH_SALT_ROUNDS=10
9+
AUTH_JWT_SCHEME=JWT
10+
AUTH_JWT_SECRET=
11+
AUTH_JWT_ISSUER=
12+
AUTH_JWT_AUDIENCE=
13+
14+
# Email
15+
EMAIL_SENDER_NAME=
16+
EMAIL_SENDER_ADDRESS=
17+
EMAIL_USER=
18+
EMAIL_PASSWORD=
19+
EMAIL_HOST=
20+
EMAIL_PORT=
21+
EMAIL_SSL=1
22+
EMAIL_TLS=
23+
24+
# Storage provider
25+
STORAGE_PROVIDER=filesystem
26+
27+
# Filesytem provider config
28+
STORAGE_PATH=data
29+
30+
# Amazon S3 provider config
31+
STORAGE_KEY=
32+
STORAGE_SECRET=
33+
STORAGE_REGION=
34+
STORAGE_BUCKET=
35+
36+
# Content Location
37+
PUBLISHED_CONTENT=repository
38+
IMPORTED_CONTENT=imported
39+
40+
# Database config
41+
DATABASE_URI=postgres://user:pass@hostname/database
42+
DATABASE_NAME=
43+
DATABASE_USER=
44+
DATABASE_PASSWORD=
45+
DATABASE_HOST=
46+
DATABASE_PORT=
47+
DATABASE_ADAPTER=postgres

.eslintignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dist

.eslintrc.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
const isDev = process.env.NODE_ENV === 'development';
2+
3+
module.exports = {
4+
root: true,
5+
parserOptions: {
6+
sourceType: 'module',
7+
ecmaVersion: 2017
8+
},
9+
// https://github.com/Flet/eslint-config-semistandard
10+
extends: ['semistandard', 'plugin:vue/recommended'],
11+
// required to lint *.vue files
12+
plugins: ['vue'],
13+
rules: {
14+
indent: ['error', 2, {
15+
SwitchCase: 1,
16+
// NOTE: Consistent indentation IS enforced;
17+
// ESlint calculated indentation start IS NOT!
18+
// https://eslint.org/docs/rules/indent#memberexpression
19+
MemberExpression: 'off'
20+
}],
21+
'arrow-parens': 'off',
22+
'no-debugger': isDev ? 'warn' : 'error',
23+
'space-before-function-paren': ['error', {
24+
anonymous: 'always',
25+
named: 'never'
26+
}],
27+
'sort-imports': ['error', { ignoreCase: true }],
28+
// Vue rules
29+
'vue/html-self-closing': 'off',
30+
'vue/attribute-hyphenation': 'off',
31+
'vue/max-attributes-per-line': ['error', { singleline: 5 }],
32+
'vue/name-property-casing': ['error', 'kebab-case'],
33+
// TODO: Add order for custom directives once supported
34+
'vue/attributes-order': ['error', {
35+
order: [
36+
'DEFINITION',
37+
'LIST_RENDERING',
38+
'CONDITIONALS',
39+
'RENDER_MODIFIERS',
40+
'UNIQUE',
41+
'BINDING',
42+
'EVENTS',
43+
'CONTENT',
44+
'GLOBAL',
45+
'OTHER_ATTR'
46+
]
47+
}],
48+
'vue/order-in-components': ['error', {
49+
order: [
50+
'el',
51+
'name',
52+
['template', 'render', 'renderError'],
53+
['parent', 'functional', 'delimiters', 'comments'],
54+
'extends',
55+
'mixins',
56+
'inheritAttrs',
57+
'model',
58+
['props', 'propsData'],
59+
'data',
60+
'computed',
61+
'methods',
62+
'watch',
63+
'LIFECYCLE_HOOKS',
64+
['directives', 'filters'],
65+
'components'
66+
]
67+
}]
68+
}
69+
};

.gitignore

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Dependencies
2+
node_modules
3+
4+
# Editors
5+
.vscode
6+
*.sublime-*
7+
.idea
8+
9+
# Logs
10+
logs
11+
*.log
12+
npm-debug.log*
13+
14+
# Configuration
15+
.env
16+
ecosystem.config.js
17+
18+
# Tailor dump storage
19+
data/*
20+
!data/.gitkeep
21+
22+
# Build artifacts
23+
dist/*
24+
!dist/.gitkeep
25+
stats.json
26+
27+
# General
28+
.DS_Store

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# APP_STARTER
2+
3+
>Under construction :construction:

client/admin/App.vue

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<template>
2+
<v-app id="app">
3+
<sidebar :drawer.sync="drawer"/>
4+
<navbar :drawer.sync="drawer"/>
5+
<v-content>
6+
<v-container fluid fill-height class="grey lighten-4">
7+
<router-view/>
8+
</v-container>
9+
</v-content>
10+
</v-app>
11+
</template>
12+
13+
<script>
14+
import Navbar from '@/admin/components/common/Navbar';
15+
import Sidebar from '@/admin/components/common/Sidebar';
16+
17+
export default {
18+
name: 'admin-app',
19+
data() {
20+
return { drawer: true };
21+
},
22+
components: { Navbar, Sidebar }
23+
};
24+
</script>
25+
26+
<style lang="scss">
27+
@import "./stylesheets/main";
28+
29+
* {
30+
box-sizing: border-box;
31+
}
32+
33+
html, body {
34+
width: 100%;
35+
height: 100%;
36+
margin: 0;
37+
padding: 0;
38+
}
39+
40+
#app {
41+
height: 100%;
42+
-webkit-font-smoothing: antialiased;
43+
-moz-osx-font-smoothing: grayscale;
44+
}
45+
46+
.v-content {
47+
background-color: #f5f5f5;
48+
}
49+
</style>

client/admin/api/user.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { extractData, processParams } from '@/common/api/helpers';
2+
import request from '@/common/api/request';
3+
4+
const url = {
5+
root: '/users',
6+
resource: it => `/users/${it.id}`,
7+
invite: it => `/users/${it.id}/invite`,
8+
import: '/users/import'
9+
};
10+
11+
function fetch(params = {}) {
12+
return request.get(url.root, { params: processParams(params) })
13+
.then(extractData);
14+
}
15+
16+
function create(item) {
17+
return request.post(url.root, item).then(extractData);
18+
}
19+
20+
function update(item) {
21+
return request.patch(url.resource(item), item).then(extractData);
22+
}
23+
24+
function remove(item) {
25+
return request.delete(url.resource(item));
26+
}
27+
28+
function invite(item) {
29+
return request.post(url.invite(item));
30+
}
31+
32+
function bulkImport(items) {
33+
return request.post(url.import, items, { responseType: 'blob' });
34+
}
35+
36+
export default {
37+
fetch,
38+
create,
39+
update,
40+
remove,
41+
invite,
42+
bulkImport
43+
};
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<template>
2+
<v-dialog v-model="show" max-width="500">
3+
<v-form @submit.prevent="executeAction">
4+
<v-card>
5+
<v-card-title class="headline">{{ heading }}</v-card-title>
6+
<v-card-text>{{ message }}</v-card-text>
7+
<v-card-actions>
8+
<v-spacer></v-spacer>
9+
<v-btn @click="close" flat>Cancel</v-btn>
10+
<v-btn color="red" flat type="submit">Yes</v-btn>
11+
</v-card-actions>
12+
</v-card>
13+
</v-form>
14+
</v-dialog>
15+
</template>
16+
17+
<script>
18+
import { withFocusTrap } from '@/common/focustrap';
19+
20+
const el = vm => vm.$children[0].$refs.dialog;
21+
22+
export default {
23+
name: 'confirmation-dialog',
24+
mixins: [withFocusTrap({ el })],
25+
props: {
26+
visible: { type: Boolean, default: false },
27+
heading: { type: String, default: '' },
28+
message: { type: String, default: 'Are you sure?' },
29+
action: { type: Function, default: () => true }
30+
},
31+
computed: {
32+
show: {
33+
get() {
34+
return this.visible;
35+
},
36+
set(value) {
37+
if (!value) this.close();
38+
}
39+
}
40+
},
41+
methods: {
42+
close() {
43+
this.$emit('update:visible', false);
44+
},
45+
executeAction() {
46+
return Promise.resolve(this.action()).then(() => {
47+
this.close();
48+
this.$emit('confirmed');
49+
});
50+
}
51+
},
52+
watch: {
53+
show(val) {
54+
this.$nextTick(() => this.focusTrap.toggle(val));
55+
}
56+
}
57+
};
58+
</script>
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<template>
2+
<v-menu
3+
:disabled="disabled"
4+
full-width
5+
min-width="290px"
6+
offset-y
7+
transition="scale-transition">
8+
<v-text-field
9+
v-validate="processedValidation"
10+
slot="activator"
11+
:name="name"
12+
:value="normalizedValue"
13+
:label="label"
14+
:disabled="disabled"
15+
:error-messages="vErrors.collect(name)"
16+
:data-vv-as="label"
17+
append-icon="mdi-calendar"
18+
readonly/>
19+
<v-date-picker :value="normalizedValue" @input="save($event)" no-title/>
20+
</v-menu>
21+
</template>
22+
23+
<script>
24+
import fecha from 'fecha';
25+
import get from 'lodash/get';
26+
import omit from 'lodash/omit';
27+
28+
const DATE_FORMAT = 'YYYY-MM-DD';
29+
30+
export default {
31+
inject: ['$validator'],
32+
props: {
33+
name: { type: String, required: true },
34+
value: { type: String, default: null },
35+
format: { type: String, default: DATE_FORMAT },
36+
validate: { type: Object, default: () => ({}) },
37+
disabled: { type: Boolean, default: false },
38+
label: { type: String, default: null }
39+
},
40+
computed: {
41+
normalizedValue() {
42+
return this.normalize(this.value, this.format, DATE_FORMAT);
43+
},
44+
processedValidation() {
45+
const { validate, format: inputFormat } = this;
46+
if (!get(validate, 'before') && !get(validate, 'after')) {
47+
return omit(validate, ['before', 'after']);
48+
}
49+
const tmp = { ...validate, date_format: DATE_FORMAT };
50+
['before', 'after'].forEach(k => {
51+
tmp[k] && (tmp[k] = this.normalize(tmp[k], inputFormat, DATE_FORMAT));
52+
});
53+
return tmp;
54+
}
55+
},
56+
methods: {
57+
save(value) {
58+
this.$emit('input', this.normalize(value, DATE_FORMAT, this.format));
59+
},
60+
normalize(value, inputFormat, outputFormat) {
61+
if (!value) return;
62+
const date = fecha.parse(value, inputFormat);
63+
return fecha.format(date, outputFormat);
64+
}
65+
}
66+
};
67+
</script>

0 commit comments

Comments
 (0)