UNCLASSIFIED
Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Open sidebar
Platform One
P
Party Bus
Launchboard
launchboard-fe
Commits
3ad4dc91
Commit
3ad4dc91
authored
May 04, 2021
by
Keith Becker
Browse files
Merge master and resolve conflicts
parents
1f552703
39d864e9
Changes
39
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
362 additions
and
433 deletions
+362
-433
package-lock.json
package-lock.json
+39
-41
src/App.vue
src/App.vue
+3
-6
src/api/http-common.js
src/api/http-common.js
+8
-4
src/api/services/schedule.js
src/api/services/schedule.js
+27
-1
src/api/services/training.js
src/api/services/training.js
+2
-1
src/components/CurriculumSchedule.vue
src/components/CurriculumSchedule.vue
+75
-34
src/components/EditableInput.vue
src/components/EditableInput.vue
+1
-3
src/components/HelpDeskSummary.vue
src/components/HelpDeskSummary.vue
+18
-8
src/components/LaunchboardSettings.vue
src/components/LaunchboardSettings.vue
+1
-6
src/components/NavBar.vue
src/components/NavBar.vue
+1
-6
src/components/PersonnelTable.vue
src/components/PersonnelTable.vue
+67
-12
src/components/ProjectsSummary.vue
src/components/ProjectsSummary.vue
+1
-10
src/components/Section.vue
src/components/Section.vue
+0
-1
src/components/Training/TrainingAttendance.vue
src/components/Training/TrainingAttendance.vue
+45
-55
src/components/TutorialTooltip.vue
src/components/TutorialTooltip.vue
+5
-0
src/components/UserSelect.vue
src/components/UserSelect.vue
+0
-5
src/plugins/vuetify.js
src/plugins/vuetify.js
+4
-2
src/router/routes.js
src/router/routes.js
+1
-13
src/scss/custom.scss
src/scss/custom.scss
+61
-220
src/scss/variables.scss
src/scss/variables.scss
+3
-5
No files found.
package-lock.json
View file @
3ad4dc91
...
@@ -99,9 +99,9 @@
...
@@ -99,9 +99,9 @@
"dev": true
"dev": true
},
},
"@babel/highlight": {
"@babel/highlight": {
"version": "7.1
2
.1
3
",
"version": "7.1
3
.1
0
",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.1
2
.1
3
.tgz",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.1
3
.1
0
.tgz",
"integrity": "sha512-
kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww
==",
"integrity": "sha512-
5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg
==",
"dev": true,
"dev": true,
"requires": {
"requires": {
"@babel/helper-validator-identifier": "^7.12.11",
"@babel/helper-validator-identifier": "^7.12.11",
...
@@ -360,9 +360,9 @@
...
@@ -360,9 +360,9 @@
"dev": true
"dev": true
},
},
"@babel/highlight": {
"@babel/highlight": {
"version": "7.1
2
.1
3
",
"version": "7.1
3
.1
0
",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.1
2
.1
3
.tgz",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.1
3
.1
0
.tgz",
"integrity": "sha512-
kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww
==",
"integrity": "sha512-
5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg
==",
"dev": true,
"dev": true,
"requires": {
"requires": {
"@babel/helper-validator-identifier": "^7.12.11",
"@babel/helper-validator-identifier": "^7.12.11",
...
@@ -651,9 +651,9 @@
...
@@ -651,9 +651,9 @@
}
}
},
},
"@babel/generator": {
"@babel/generator": {
"version": "7.13.
0
",
"version": "7.13.
9
",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.
0
.tgz",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.
9
.tgz",
"integrity": "sha512-
zBZfgvBB/ywjx0Rgc2+BwoH/3H+lDtlgD4hBOpEv5LxRnYsm/753iRuLepqnYlynpjC3AdQxtxsoeHJoEEwOA
w==",
"integrity": "sha512-
mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+S
w==",
"dev": true,
"dev": true,
"requires": {
"requires": {
"@babel/types": "^7.13.0",
"@babel/types": "^7.13.0",
...
@@ -1367,9 +1367,9 @@
...
@@ -1367,9 +1367,9 @@
"dev": true
"dev": true
},
},
"@babel/highlight": {
"@babel/highlight": {
"version": "7.1
2
.1
3
",
"version": "7.1
3
.1
0
",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.1
2
.1
3
.tgz",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.1
3
.1
0
.tgz",
"integrity": "sha512-
kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww
==",
"integrity": "sha512-
5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg
==",
"dev": true,
"dev": true,
"requires": {
"requires": {
"@babel/helper-validator-identifier": "^7.12.11",
"@babel/helper-validator-identifier": "^7.12.11",
...
@@ -1977,9 +1977,9 @@
...
@@ -1977,9 +1977,9 @@
"dev": true
"dev": true
},
},
"@babel/highlight": {
"@babel/highlight": {
"version": "7.1
2
.1
3
",
"version": "7.1
3
.1
0
",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.1
2
.1
3
.tgz",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.1
3
.1
0
.tgz",
"integrity": "sha512-
kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww
==",
"integrity": "sha512-
5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg
==",
"dev": true,
"dev": true,
"requires": {
"requires": {
"@babel/helper-validator-identifier": "^7.12.11",
"@babel/helper-validator-identifier": "^7.12.11",
...
@@ -1988,9 +1988,9 @@
...
@@ -1988,9 +1988,9 @@
}
}
},
},
"@babel/parser": {
"@babel/parser": {
"version": "7.13.
4
",
"version": "7.13.
13
",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.
4
.tgz",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.
13
.tgz",
"integrity": "sha512-
uvoOulWHhI+0+1f9L4BoozY7U5cIkZ9PgJqvb041d6vypgUmtVPG4vmGm4pSggjl8BELzvHyUeJSUyEMY6b+qA
==",
"integrity": "sha512-
OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw
==",
"dev": true
"dev": true
},
},
"@babel/template": {
"@babel/template": {
...
@@ -2960,9 +2960,9 @@
...
@@ -2960,9 +2960,9 @@
}
}
},
},
"semver": {
"semver": {
"version": "7.3.
4
",
"version": "7.3.
5
",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.
4
.tgz",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.
5
.tgz",
"integrity": "sha512-
tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw
==",
"integrity": "sha512-
PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ
==",
"dev": true,
"dev": true,
"requires": {
"requires": {
"lru-cache": "^6.0.0"
"lru-cache": "^6.0.0"
...
@@ -6334,9 +6334,9 @@
...
@@ -6334,9 +6334,9 @@
"dev": true
"dev": true
},
},
"string-width": {
"string-width": {
"version": "4.2.
0
",
"version": "4.2.
2
",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.
0
.tgz",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.
2
.tgz",
"integrity": "sha512-
zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg
==",
"integrity": "sha512-
XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA
==",
"dev": true,
"dev": true,
"requires": {
"requires": {
"emoji-regex": "^8.0.0",
"emoji-regex": "^8.0.0",
...
@@ -7766,9 +7766,9 @@
...
@@ -7766,9 +7766,9 @@
}
}
},
},
"is-path-inside": {
"is-path-inside": {
"version": "3.0.
2
",
"version": "3.0.
3
",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.
2
.tgz",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.
3
.tgz",
"integrity": "sha512-
/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg
==",
"integrity": "sha512-
Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ
==",
"dev": true
"dev": true
},
},
"is-stream": {
"is-stream": {
...
@@ -8041,9 +8041,9 @@
...
@@ -8041,9 +8041,9 @@
}
}
},
},
"rxjs": {
"rxjs": {
"version": "6.6.
3
",
"version": "6.6.
7
",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.
3
.tgz",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.
7
.tgz",
"integrity": "sha512-
trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZ
Q==",
"integrity": "sha512-
hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvR
Q==",
"dev": true,
"dev": true,
"requires": {
"requires": {
"tslib": "^1.9.0"
"tslib": "^1.9.0"
...
@@ -13570,9 +13570,9 @@
...
@@ -13570,9 +13570,9 @@
}
}
},
},
"semver": {
"semver": {
"version": "7.3.
4
",
"version": "7.3.
5
",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.
4
.tgz",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.
5
.tgz",
"integrity": "sha512-
tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw
==",
"integrity": "sha512-
PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ
==",
"dev": true,
"dev": true,
"requires": {
"requires": {
"lru-cache": "^6.0.0"
"lru-cache": "^6.0.0"
...
@@ -19666,6 +19666,12 @@
...
@@ -19666,6 +19666,12 @@
"yargs-parser": "10.x"
"yargs-parser": "10.x"
},
},
"dependencies": {
"dependencies": {
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true
},
"yargs-parser": {
"yargs-parser": {
"version": "18.1.3",
"version": "18.1.3",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
...
@@ -19674,14 +19680,6 @@
...
@@ -19674,14 +19680,6 @@
"requires": {
"requires": {
"camelcase": "^5.0.0",
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
"decamelize": "^1.2.0"
},
"dependencies": {
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true
}
}
}
}
}
}
}
...
...
src/App.vue
View file @
3ad4dc91
<
template
>
<
template
>
<v-app>
<v-app>
<TutorialTooltip
/>
<TutorialTooltip
/>
<ErrorDialog
/>
<NavBar
/>
<NavBar
/>
<v-main
id=
"main-container"
fluid
>
<v-main
id=
"main-container"
fluid
>
<router-view
id=
"main-content"
/>
<router-view
id=
"main-content"
/>
...
@@ -13,10 +14,11 @@
...
@@ -13,10 +14,11 @@
import
NavBar
from
"
@/components/NavBar.vue
"
;
import
NavBar
from
"
@/components/NavBar.vue
"
;
import
Footer
from
"
@/components/Footer.vue
"
;
import
Footer
from
"
@/components/Footer.vue
"
;
import
TutorialTooltip
from
"
@/components/TutorialTooltip.vue
"
;
import
TutorialTooltip
from
"
@/components/TutorialTooltip.vue
"
;
import
ErrorDialog
from
"
@/components/APIErrorDialog
"
;
export
default
{
export
default
{
name
:
"
App
"
,
name
:
"
App
"
,
components
:
{
NavBar
,
Footer
,
TutorialTooltip
},
components
:
{
NavBar
,
Footer
,
TutorialTooltip
,
ErrorDialog
},
created
()
{
created
()
{
this
.
syncDarkMode
();
this
.
syncDarkMode
();
},
},
...
@@ -121,11 +123,6 @@ export default {
...
@@ -121,11 +123,6 @@ export default {
}
}
}
}
.v-btn
:not
(
.v-btn--outlined
)
.primary
{
color
:
$button-text-color
;
border
:
$button-border
;
}
// fade-in animation
// fade-in animation
.v-application--wrap
{
.v-application--wrap
{
animation
:
fade-in
3s
forwards
;
animation
:
fade-in
3s
forwards
;
...
...
src/api/http-common.js
View file @
3ad4dc91
import
axios
from
"
axios
"
;
import
axios
from
"
axios
"
;
export
const
HTTP
=
axios
.
create
({
export
const
createBaseHttp
=
()
=>
{
baseURL
:
process
.
env
.
VUE_APP_API_BASE_URL
,
return
axios
.
create
({
// add headers or common stuff here
baseURL
:
process
.
env
.
VUE_APP_API_BASE_URL
,
});
// add headers or common stuff here
});
};
export
const
HTTP
=
createBaseHttp
();
HTTP
.
interceptors
.
response
.
use
((
response
)
=>
response
?.
data
?.
result
);
HTTP
.
interceptors
.
response
.
use
((
response
)
=>
response
?.
data
?.
result
);
src/api/services/schedule.js
View file @
3ad4dc91
import
{
HTTP
}
from
"
@/api/http-common
"
;
import
{
HTTP
,
createBaseHttp
}
from
"
@/api/http-common
"
;
import
download
from
"
downloadjs
"
;
const
defaultCertificateFileName
=
"
certificate.pdf
"
;
export
default
{
export
default
{
defaultCertificateFileName
,
async
getScheduleForUser
()
{
async
getScheduleForUser
()
{
return
await
HTTP
.
get
(
"
/courses/my-registrations
"
);
return
await
HTTP
.
get
(
"
/courses/my-registrations
"
);
},
},
async
downloadCertificate
(
courseId
,
userId
)
{
const
certificateHTTP
=
createBaseHttp
();
// fetch the cert bytes
// no need to stream since the certificate is a fixed small size
const
response
=
await
certificateHTTP
.
get
(
`/courses/
${
courseId
}
/registrations/
${
userId
}
/certificate`
,
{
responseType
:
"
blob
"
}
);
// determine filename
let
filename
;
try
{
filename
=
response
.
headers
[
"
content-disposition
"
]
.
split
(
"
filename=
"
)[
1
]
.
replace
(
/"/g
,
""
);
}
catch
(
e
)
{
// issue parsing header, default to simple file name
filename
=
defaultCertificateFileName
;
}
// save to disk
download
(
response
.
data
,
filename
,
response
.
headers
[
"
content-type
"
]);
},
};
};
src/api/services/training.js
View file @
3ad4dc91
...
@@ -68,9 +68,10 @@ export default {
...
@@ -68,9 +68,10 @@ export default {
window
.
open
(
"
/api/courses/export
"
);
window
.
open
(
"
/api/courses/export
"
);
},
},
async
getCourseRegistrationsById
(
courseId
,
params
)
{
async
getCourseRegistrationsById
(
courseId
,
params
)
{
return
await
HTTP
.
get
(
`/courses/
${
courseId
}
/registrations`
,
{
const
response
=
await
HTTP
.
get
(
`/courses/
${
courseId
}
/registrations`
,
{
params
,
params
,
});
});
return
response
;
},
},
async
setUserAttendance
(
courseId
,
body
)
{
async
setUserAttendance
(
courseId
,
body
)
{
return
await
HTTP
.
put
(
return
await
HTTP
.
put
(
...
...
src/components/CurriculumSchedule.vue
View file @
3ad4dc91
<
template
>
<
template
>
<v-container
class=
"curriculum-schedule text-left px-
2
"
>
<v-container
class=
"curriculum-schedule text-left px-
4
"
>
<v-skeleton-loader
:loading=
"loading"
type=
"paragraph@5"
class=
"w-100"
>
<v-skeleton-loader
:loading=
"loading"
type=
"paragraph@5"
class=
"w-100"
>
<v-card
v-if=
"
emptyString
"
>
<v-card
v-if=
"
registrations.length === 0
"
>
<v-card-title>
You currently don't have any c
las
ses!
</v-card-title>
<v-card-title>
You currently don't have any c
our
ses!
</v-card-title>
<v-card-text>
Your scheduled c
las
ses will appear here.
</v-card-text>
<v-card-text>
Your scheduled c
our
ses will appear here.
</v-card-text>
</v-card>
</v-card>
<Error
Message
v-if=
"error"
v-bind:errorMessage=
"errorMessage"
/>
<Error
Card
v-if=
"error"
v-bind:errorMessage=
"errorMessage"
/>
<
v-container
class=
"px-6"
v-else
>
<
div
v-else
>
<div
<div
v-for=
"(item, index) in
schedule
"
v-for=
"(item, index) in
registrations
"
:key=
"index"
:key=
"index"
class=
"d-flex flex-
wrap
flex-sm-
n
ow
rap text-left pb-3
"
class=
"d-flex flex-
column
flex-sm-
r
ow
px-4 course-row
"
>
>
<div
class=
"d-flex"
>
<div
<div
class=
"col-4 d-inline-block d-flex align-start"
>
class=
"d-flex flex-column flex-grow-1 pr-0 pr-sm-10 pb-3 pb-sm-0"
{{
item
.
title
}}
>
<div
class=
"subhead"
>
{{
item
.
course
.
name
}}
</div>
</div>
<div
class=
"col-8 d-inline-block"
>
<div>
{{
item
.
description
}}
{{
item
.
course
.
description
}}
</div>
</div>
</div>
</div>
<v-spacer
class=
"d-none d-sm-flex"
/>
<div
class=
"text-center"
>
<v-btn
<v-tooltip
top
v-if=
"item.completed"
>
color=
"secondary"
<template
v-slot:activator=
"
{ on, attrs }">
href=
"https://www.galvanize.com/"
<v-btn
target=
"_blank"
color=
"secondary"
class=
"mx-auto mt-2 mr-sm-2 no-link"
@
click=
"getCertificate(item.course)"
>
target=
"_blank"
Go to Learn
v-bind=
"attrs"
</v-btn>
v-on=
"on"
>
<v-icon
left
>
mdi-download
</v-icon>
Certificate
</v-btn>
</
template
>
<span>
Download Certificate of Completion for
{{ item.course.name }}
</span>
</v-tooltip>
<v-btn
v-else
color=
"secondary"
href=
"https://www.galvanize.com/"
target=
"_blank"
class=
"no-link"
>
Go to Learn
</v-btn>
</div>
</div>
</div>
</
v-container
>
</
div
>
</v-skeleton-loader>
</v-skeleton-loader>
</v-container>
</v-container>
</template>
</template>
<
script
>
<
script
>
import
ScheduleService
from
"
@/api/services/schedule
"
;
import
ScheduleService
from
"
@/api/services/schedule
"
;
import
{
SET_ERROR_MESSAGE
}
from
"
@/store/mutation-types
"
;
import
{
SET_ERROR_MESSAGE
,
SET_ERROR_DIALOG
}
from
"
@/store/mutation-types
"
;
import
Error
Message
from
"
@/components/APIErrorCard
"
;
import
Error
Card
from
"
@/components/APIErrorCard
"
;
export
default
{
export
default
{
components
:
{
components
:
{
Error
Message
,
Error
Card
,
},
},
data
:
()
=>
({
data
:
()
=>
({
loading
:
false
,
loading
:
false
,
schedule
:
[],
registrations
:
[],
emptyString
:
false
,
error
:
false
,
error
:
false
,
errorMessage
:
""
,
errorMessage
:
""
,
}),
}),
...
@@ -54,10 +76,7 @@ export default {
...
@@ -54,10 +76,7 @@ export default {
try
{
try
{
this
.
loading
=
true
;
this
.
loading
=
true
;
const
response
=
await
ScheduleService
.
getScheduleForUser
();
const
response
=
await
ScheduleService
.
getScheduleForUser
();
this
.
schedule
=
response
.
registrations
;
this
.
registrations
=
response
.
registrations
;
if
(
this
.
schedule
.
length
===
0
)
{
this
.
emptyString
=
true
;
}
}
catch
(
error
)
{
}
catch
(
error
)
{
this
.
error
=
true
;
this
.
error
=
true
;
this
.
$store
.
commit
(
SET_ERROR_MESSAGE
,
error
);
this
.
$store
.
commit
(
SET_ERROR_MESSAGE
,
error
);
...
@@ -67,11 +86,33 @@ export default {
...
@@ -67,11 +86,33 @@ export default {
this
.
loading
=
false
;
this
.
loading
=
false
;
}
}
},
},
methods
:
{
async
getCertificate
(
course
)
{
try
{
await
ScheduleService
.
downloadCertificate
(
course
.
id
,
this
.
$store
.
state
.
user
.
user
.
id
);
}
catch
(
error
)
{
this
.
$store
.
commit
(
SET_ERROR_MESSAGE
,
error
);
this
.
$store
.
commit
(
SET_ERROR_DIALOG
,
true
);
console
.
error
(
error
);
}
},
},
};
};
</
script
>
</
script
>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
.curriculum-schedule
{
.theme--dark
{
position
:
relative
;
.v-btn.secondary
{
&
,
.v-icon
{
color
:
#000000
;
}
}
}
.curriculum-schedule
.course-row
:not
(
:last-child
)
{
padding-bottom
:
32px
;
}
}
</
style
>
</
style
>
src/components/EditableInput.vue
View file @
3ad4dc91
...
@@ -167,9 +167,7 @@ export default {
...
@@ -167,9 +167,7 @@ export default {
.mt-n5px
{
.mt-n5px
{
margin-top
:
-5px
;
margin-top
:
-5px
;
}
}
.theme--dark.v-text-field.no-border
.theme--dark.v-text-field
>
.v-input__control
>
.v-input__slot
:before
{
>
.v-input__control
>
.v-input__slot
:before
{
border-color
:
transparent
!
important
;
border-color
:
transparent
!
important
;
display
:
none
;
display
:
none
;
}
}
...
...
src/components/HelpDeskSummary.vue
View file @
3ad4dc91
<
template
>
<
template
>
<v-container
class=
"help-desk-summary text-center px-8"
>
<v-container
class=
"help-desk-summary text-center px-8"
>
<div
class=
"support-row d-flex flex-wrap flex-sm-nowrap text-left pb-8"
>
<div
class=
"support-row d-flex flex-wrap flex-sm-nowrap text-left pb-8"
>
<div
class=
"pr-
0
pr-sm-10 pb-3 pb-md-0"
>
<div
class=
"pr-
2
pr-sm-10 pb-3 pb-md-0"
>
<div
class=
"subhead"
>
Platform One Support Hub
</div>
<div
class=
"subhead"
>
Platform One Support Hub
</div>
Any problems or requests regarding accounts, cybersecurity, or other
Any problems or requests regarding accounts, cybersecurity, or other
features can be issued here.
features can be issued here.
</div>
</div>
<v-spacer
class=
"d-none d-sm-flex"
/>
<v-spacer
class=
"d-none d-sm-flex"
/>
<v-btn
<v-btn
color=
"
second
ary"
color=
"
prim
ary"
href=
"https://jira.il2.dso.mil/servicedesk/customer/portal/1"
href=
"https://jira.il2.dso.mil/servicedesk/customer/portal/1"
target=
"_blank"
target=
"_blank"
class=
"mx-auto no-link"
class=
"mx-auto no-link"
>
>
Issue
Ticket
Submit
Ticket
</v-btn>
</v-btn>
</div>
</div>
<div
class=
"support-row d-flex flex-wrap flex-sm-nowrap text-left"
>
<div
class=
"support-row d-flex flex-wrap flex-sm-nowrap text-left
pb-8
"
>
<div
class=
"pr-
0
pr-sm-10 pb-3 pb-sm-0"
>
<div
class=
"pr-
2
pr-sm-10 pb-3 pb-sm-0"
>
<div
class=
"subhead"
>
Platform One General Help
</div>
<div
class=
"subhead"
>
Platform One General Help
</div>
Can't find a support form that meets your needs?
Can't find a support form that meets your needs?
<br
/>
<br
/>
Email us at
Email us at
<a
href=
"mailto:help@dso.mil"
target=
"_blank"
>
help@dso.mil
</a>
<a
href=
"mailto:help@dso.mil"
target=
"_blank"
>
help@dso.mil
</a>
</div>
</div>
<v-spacer
/>
<v-spacer
class=
"d-none d-sm-flex"
/>
<v-btn
<v-btn
outlined
color=
"tertiary"
color=
"secondary"
href=
"mailto:help@dso.mil"
href=
"mailto:help@dso.mil"
target=
"_blank"
target=
"_blank"
class=
"mx-auto"
class=
"mx-auto"
...
@@ -35,5 +34,16 @@
...
@@ -35,5 +34,16 @@
Email
Email
</v-btn>
</v-btn>
</div>
</div>
<div
class=
"support-row d-flex flex-wrap flex-sm-nowrap text-left"
>
<div
class=
"pr-2 pr-sm-10 pb-3 pb-sm-0"
>
<div
class=
"subhead"
>
Launchboard Support
</div>
Submit a feature request or provide feedback on how we can improve your
experience
</div>
<v-spacer
class=
"d-none d-sm-flex"
/>
<v-btn
color=
"primary"
:disabled=
"true"
class=
"mx-auto"
>
Coming Soon
</v-btn>
</div>
</v-container>
</v-container>
</
template
>
</
template
>
src/components/LaunchboardSettings.vue
View file @
3ad4dc91
<
template
>
<
template
>
<div>
<div>
<div
class=
"d-flex pb-3"
>
<div
class=
"d-flex pb-3"
>
<ErrorMessage
/>
<v-avatar
class=
"mr-4"
size=
"168"
>
<v-avatar
class=
"mr-4"
size=
"168"
>
<img
v-if=
"user.avatar"
:src=
"user.avatar"
:alt=
"user.name"
/>
<img
v-if=
"user.avatar"
:src=
"user.avatar"
:alt=
"user.name"
/>
<v-icon
v-else
>
mdi-account-circle
</v-icon>
<v-icon
v-else
>
mdi-account-circle
</v-icon>
...
@@ -14,7 +13,7 @@
...
@@ -14,7 +13,7 @@
<v-btn
<v-btn
icon
icon
color=
"secondary"
color=
"secondary"
class=
"
no-border no-shadow
no-link"
class=
"no-link"
v-bind=
"attrs"
v-bind=
"attrs"
v-on=
"on"
v-on=
"on"
href=
"https://login.dso.mil/auth/realms/baby-yoda/account/"
href=
"https://login.dso.mil/auth/realms/baby-yoda/account/"
...
@@ -70,12 +69,8 @@
...
@@ -70,12 +69,8 @@
<
script
>
<
script
>
import
{
CALL_SET_USER_PREFERENCE
}
from
"
@/store/action-types
"
;
import
{
CALL_SET_USER_PREFERENCE
}
from
"
@/store/action-types
"
;
import
{
SET_ERROR_MESSAGE
,
SET_ERROR_DIALOG
}
from
"
@/store/mutation-types
"
;
import
{
SET_ERROR_MESSAGE
,
SET_ERROR_DIALOG
}
from
"
@/store/mutation-types
"
;
import
ErrorMessage
from
"
@/components/APIErrorDialog
"
;
export
default
{
export
default
{
components
:
{
ErrorMessage
,
},
data
:
()
=>
({
data
:
()
=>
({
user
:
{},
user
:
{},
darkMode
:
true
,
darkMode
:
true
,
...
...
src/components/NavBar.vue
View file @
3ad4dc91
...
@@ -41,12 +41,7 @@
...
@@ -41,12 +41,7 @@
</router-link>
</router-link>
</div>
</div>
</v-toolbar-items>
</v-toolbar-items>
<v-btn
<v-btn
icon
class=
"no-link nav-item"
id=
"settings-button"
to=
"/settings"
>
icon
class=
"no-shadow no-border no-link nav-item"
id=
"settings-button"
to=
"/settings"
>
<v-icon>
mdi-cog
</v-icon>
<v-icon>
mdi-cog
</v-icon>
</v-btn>
</v-btn>
<v-app-bar-nav-icon
<v-app-bar-nav-icon
...
...
src/components/PersonnelTable.vue
View file @
3ad4dc91
<
template
>
<
template
>
<div>
<div>
<v-dialog
v-model=
"displayUserPermissionDialog"
persistent
width=
"500"
hide-overlay
id=
"user-permission-dialog"
>
<v-card
class=
"ma-0"
>
<v-card-title>
Confirm Permission Change
</v-card-title>
<v-card-text
class=
"text-left"
>
Are you sure you want to change your permission to "
{{
permissionUserData
.
permission
}}
"?
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color=
"secondary"
@
click=
"cancelUserPermissionChange"
>
Cancel
</v-btn>
<v-btn
color=
"primary"
@
click=
"confirmUserPermissionChange"
>
Confirm
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<div
<div
class=
"d-flex flex-wrap flex-sm-nowrap px-2 px-sm-4 mb-4 justify-space-between"
class=
"d-flex flex-wrap flex-sm-nowrap px-2 px-sm-4 mb-4 justify-space-between"
>
>
<ErrorMessage
/>
<div
class=
"text-left"
>
<div
class=
"text-left"
>
<h2
class=
"px-0 mb-2 subhead"
>
{{
title
}}
</h2>
<h2
class=
"px-0 mb-2 subhead"
>
{{
title
}}
</h2>
</div>
</div>
...
@@ -36,7 +62,8 @@
...
@@ -36,7 +62,8 @@
<v-btn
<v-btn
@
click=
"removePersonnel"
@
click=
"removePersonnel"
:disabled=
"personnel.selectedPersonnel.length === 0"
:disabled=
"personnel.selectedPersonnel.length === 0"
class=
"mr-3 table-action-btn"
class=
"mr-3"
color=
"accent"
>
>
<v-icon
class=
"mr-2"
>
mdi-trash-can
</v-icon>
<v-icon
class=
"mr-2"
>
mdi-trash-can
</v-icon>
Remove Selected
Remove Selected
...
@@ -44,7 +71,8 @@
...
@@ -44,7 +71,8 @@
<v-btn
<v-btn
@
click=
"sendEmailToPersonnel"
@
click=
"sendEmailToPersonnel"
:disabled=
"personnel.selectedPersonnel.length === 0"
:disabled=
"personnel.selectedPersonnel.length === 0"
class=
"mr-3 table-action-btn"
class=
"mr-3"
color=
"accent"
>
>
<v-icon
class=
"mr-2"
>
mdi-pencil
</v-icon>
<v-icon
class=
"mr-2"
>
mdi-pencil
</v-icon>
Email Selected
Email Selected
...
@@ -68,8 +96,11 @@ import {
...
@@ -68,8 +96,11 @@ import {
DEFAULT_TABLE_OPTIONS
,
DEFAULT_TABLE_OPTIONS
,
}
from
"
@/config/table-constants
"
;
}
from
"
@/config/table-constants
"
;
import
{
createDefaultPaginationParams
}
from
"
@/utils/tableHelpers
"
;
import
{
createDefaultPaginationParams
}
from
"
@/utils/tableHelpers
"
;
import
ErrorMessage
from
"
@/components/APIErrorDialog
"
;
import
{
import
{
SET_ERROR_MESSAGE
,
SET_ERROR_DIALOG
}
from
"
@/store/mutation-types
"
;
SET_USER
,
SET_ERROR_MESSAGE
,
SET_ERROR_DIALOG
,
}
from
"
@/store/mutation-types
"
;
export
default
{
export
default
{
name
:
"
PersonnelTable
"
,
name
:
"
PersonnelTable
"
,
...
@@ -89,9 +120,6 @@ export default {
...
@@ -89,9 +120,6 @@ export default {
type
:
String
,
type
:
String
,
},
},
},
},
components
:
{
ErrorMessage
,
},
data
()
{
data
()
{
return
{
return
{
inputRules
,
inputRules
,
...
@@ -144,6 +172,8 @@ export default {
...
@@ -144,6 +172,8 @@ export default {
],
],
},
},
permissionTypes
:
Permission
,
permissionTypes
:
Permission
,
displayUserPermissionDialog
:
false
,
permissionUserData
:
{},
};
};
},
},
async
mounted
()
{
async
mounted
()
{
...
@@ -183,7 +213,6 @@ export default {
...
@@ -183,7 +213,6 @@ export default {
}
catch
(
error
)
{
}
catch
(
error
)
{
this
.
$store
.
commit
(
SET_ERROR_MESSAGE
,
error
);
this
.
$store
.
commit
(
SET_ERROR_MESSAGE
,
error
);
this
.
$store
.
commit
(
SET_ERROR_DIALOG
,
true
);
this
.
$store
.
commit
(
SET_ERROR_DIALOG
,
true
);
console
.
error
(
"
!personnel error!
"
,
error
);
}
finally
{
}
finally
{
this
.
loading
=
false
;
this
.
loading
=
false
;
this
.
fetchingData
=
false
;
this
.
fetchingData
=
false
;
...
@@ -206,7 +235,6 @@ export default {
...
@@ -206,7 +235,6 @@ export default {
await
this
.
fetchData
({});
await
this
.
fetchData
({});
this
.
personnel
.
selectedPersonnel
=
[];
this
.
personnel
.
selectedPersonnel
=
[];
}
catch
(
e
)
{
}
catch
(
e
)
{
console
.
error
(
"
!personnel error!
"
,
e
);
this
.
$store
.
commit
(
SET_ERROR_MESSAGE
,
e
);
this
.
$store
.
commit
(
SET_ERROR_MESSAGE
,
e
);
this
.
$store
.
commit
(
SET_ERROR_DIALOG
,
true
);
this
.
$store
.
commit
(
SET_ERROR_DIALOG
,
true
);
}
}
...
@@ -225,8 +253,35 @@ export default {
...
@@ -225,8 +253,35 @@ export default {
getPersonnelListItems
()
{
getPersonnelListItems
()
{
return
this
.
personnel
.
listItems
;
return
this
.
personnel
.
listItems
;
},
},
async
updateUserPermissions
(
userData
)
{
updateUserPermissions
(
userData
)
{
UserService
.
updateUserPermission
([
userData
]);
this
.
permissionUserData
=
userData
;
if
(
this
.
$store
.
state
.
user
.
user
.
name
===
userData
.
name
)
{
this
.
displayUserPermissionDialog
=
true
;
}
else
{
this
.
setUserPermissions
(
userData
);
}
},
async
setUserPermissions
(
userData
,
activeUser
)
{
try
{
await
UserService
.
updateUserPermission
([
userData
]);
if
(
activeUser
)
{
const
user
=
await
UserService
.
getUser
();
this
.
$store
.
commit
(
SET_USER
,
user
);
this
.
$router
.
push
({
name
:
"
Launchboard
"
});
}
}
catch
(
e
)
{
this
.
$store
.
commit
(
SET_ERROR_MESSAGE
,
e
);
this
.
$store
.
commit
(
SET_ERROR_DIALOG
,
true
);
this
.
fetchData
({});
}
},
cancelUserPermissionChange
()
{
this
.
fetchData
({});
this
.
displayUserPermissionDialog
=
false
;
},
confirmUserPermissionChange
()
{
this
.
setUserPermissions
(
this
.
permissionUserData
,
true
);
this
.
displayUserPermissionDialog
=
false
;
},
},
},
},
watch
:
{
watch
:
{
...
...
src/components/ProjectsSummary.vue
View file @
3ad4dc91
...
@@ -61,12 +61,7 @@
...
@@ -61,12 +61,7 @@
<!-- dots menu visible in xs -->
<!-- dots menu visible in xs -->
<v-menu
left
content-class=
"project-summary-menu"
>
<v-menu
left
content-class=
"project-summary-menu"
>
<
template
v-slot:activator=
"{ on, attrs }"
>
<
template
v-slot:activator=
"{ on, attrs }"
>
<v-btn
<v-btn
icon
v-bind=
"attrs"
v-on=
"on"
class=
"d-sm-none"
>
icon
v-bind=
"attrs"
v-on=
"on"
class=
"d-sm-none no-border no-shadow"
>
<v-icon>
mdi-dots-vertical
</v-icon>
<v-icon>
mdi-dots-vertical
</v-icon>
</v-btn>
</v-btn>
</
template
>
</
template
>
...
@@ -136,7 +131,6 @@
...
@@ -136,7 +131,6 @@
v-on=
"on"
v-on=
"on"
@
click.native.stop
@
click.native.stop
color=
"secondary"
color=
"secondary"
class=
"no-border no-shadow"
>
>
<v-icon
small
>
$vuetify.icons.gitlab
</v-icon>
<v-icon
small
>
$vuetify.icons.gitlab
</v-icon>
</v-btn>
</v-btn>
...
@@ -154,7 +148,6 @@
...
@@ -154,7 +148,6 @@
v-on=
"on"
v-on=
"on"
@
click.native.stop
@
click.native.stop
color=
"secondary"
color=
"secondary"
class=
"no-border no-shadow"
>
>
<GitLabIcon
class=
"icon small"
icon=
"rocket"
/>
<GitLabIcon
class=
"icon small"
icon=
"rocket"
/>
</v-btn>
</v-btn>
...
@@ -172,7 +165,6 @@
...
@@ -172,7 +165,6 @@
v-on=
"on"
v-on=
"on"
@
click.native.stop
@
click.native.stop
color=
"secondary"
color=
"secondary"
class=
"no-border no-shadow"
>
>
<v-icon
small
>
$vuetify.icons.jira
</v-icon>
<v-icon
small
>
$vuetify.icons.jira
</v-icon>
</v-btn>
</v-btn>
...
@@ -190,7 +182,6 @@
...
@@ -190,7 +182,6 @@
v-on=
"on"
v-on=
"on"
@
click.native.stop
@
click.native.stop
color=
"secondary"
color=
"secondary"
class=
"no-border no-shadow"
>
>
<v-icon
small
>
$vuetify.icons.confluence
</v-icon>
<v-icon
small
>
$vuetify.icons.confluence
</v-icon>
</v-btn>
</v-btn>
...
...
src/components/Section.vue
View file @
3ad4dc91
...
@@ -5,7 +5,6 @@
...
@@ -5,7 +5,6 @@
<v-spacer
/>
<v-spacer
/>
<slot
name=
"header-right"
></slot>
<slot
name=
"header-right"
></slot>
<v-btn
<v-btn
class=
"no-shadow no-border"
v-if=
"!hideCollapse && !hideCollapseButton"
v-if=
"!hideCollapse && !hideCollapseButton"
icon
icon
@
click=
"isCollapsed = !isCollapsed"
@
click=
"isCollapsed = !isCollapsed"
...
...
src/components/Training/TrainingAttendance.vue
View file @
3ad4dc91
<
template
>
<
template
>
<div>
<v-container>
<div
<v-row>
class=
"d-flex flex-wrap flex-sm-nowrap px-2 px-sm-4 mb-4 justify-space-between"
<v-col>
>
<h2
class=
"text-left px-0 my-0"
>
Students
</h2>
<div
class=
"text-left"
>
</v-col>
<h2
class=
"px-0 mb-2 subhead"
>
Students
</h2>
</v-row>
</div>
<v-row
class=
"filter-wrapper filter-input mb-4"
>
</div>
<v-col
cols=
"12"
sm=
"6"
md=
"3"
>
<v-text-field
v-model=
"search"
ref=
"filterSearch"
append-icon=
"mdi-magnify"
@
keyup=
"fetchDebounced"
@
click:append=
"setInputElementFocus($refs.filterSearch)"
placeholder=
"Search"
single-line
hide-details
></v-text-field>
</v-col>
</v-row>
<v-data-table
<v-data-table
v-if=
"headers"
v-if=
"headers"
v-model=
"selectedUsers"
v-model=
"selectedUsers"
:headers=
"headers"
:headers=
"headers"
:items=
"listItems"
:items=
"listItems"
:search=
"search"
show-select
show-select
mobile-breakpoint=
"800"
mobile-breakpoint=
"800"
:options.sync=
"options"
:options.sync=
"options"
...
@@ -85,11 +98,12 @@
...
@@ -85,11 +98,12 @@
<span
v-bind:key=
"h.value"
v-else
>
{{ h.text }}
</span>
<span
v-bind:key=
"h.value"
v-else
>
{{ h.text }}
</span>
</template>
</template>
</v-data-table>
</v-data-table>
<div
class=
"d-flex flex-wrap mt-5
table-action-btn
"
>
<div
class=
"d-flex flex-wrap mt-5"
>
<v-btn
<v-btn
@
click=
"removeSelectedStudent"
@
click=
"removeSelectedStudent"
:disabled=
"selectedUsers.length === 0"
:disabled=
"selectedUsers.length === 0"
class=
"mr-3 table-action-btn"
class=
"mr-3"
color=
"accent"
>
>
<v-icon
class=
"mr-2"
>
mdi-trash-can
</v-icon>
<v-icon
class=
"mr-2"
>
mdi-trash-can
</v-icon>
Remove Selected
Remove Selected
...
@@ -97,22 +111,12 @@
...
@@ -97,22 +111,12 @@
<v-btn
<v-btn
@
click=
"sendEmailToStudents"
@
click=
"sendEmailToStudents"
:disabled=
"selectedUsers.length === 0"
:disabled=
"selectedUsers.length === 0"
class=
"mr-3 table-action-btn"
class=
"mr-3"
color=
"accent"
>
>
<v-icon
class=
"mr-2"
>
mdi-pencil
</v-icon>
<v-icon
class=
"mr-2"
>
mdi-pencil
</v-icon>
Email Selected
Email Selected
</v-btn>
</v-btn>
<div
class=
"d-flex flex-column mr-n4 mt-n1 ml-auto"
>
<v-btn
text
color=
"secondary"
class=
"no-border no-shadow"
@
click=
"state.isAddingStudent = true"
>
<v-icon
class=
"mr-2"
>
mdi-plus-circle
</v-icon>
<h4
class=
"px-0 ma-0"
>
Add Student
</h4>
</v-btn>
</div>
</div>
</div>
<AddStudentsToCourseDialog
<AddStudentsToCourseDialog
:course-id=
"currentCourseId"
:course-id=
"currentCourseId"
...
@@ -120,7 +124,7 @@
...
@@ -120,7 +124,7 @@
v-on:close-dialog=
"closeAddStudentDialog"
v-on:close-dialog=
"closeAddStudentDialog"
v-on:update-students=
"fetchDebounced"
v-on:update-students=
"fetchDebounced"
/>
/>
</
div
>
</
v-container
>
</template>
</template>
<
script
>
<
script
>
...
@@ -148,9 +152,14 @@ export default {
...
@@ -148,9 +152,14 @@ export default {
type
:
Object
,
type
:
Object
,
required
:
true
,
required
:
true
,
},
},
reload
:
{
type
:
Number
,
},
},
},
data
()
{
data
()
{
return
{
return
{
search
:
""
,
darkMode
:
null
,
inputRules
,
inputRules
,
loading
:
false
,
loading
:
false
,
total
:
0
,
total
:
0
,
...
@@ -171,12 +180,10 @@ export default {
...
@@ -171,12 +180,10 @@ export default {
};
};
},
},
async
mounted
()
{
async
mounted
()
{
this
.
darkMode
=
this
.
$vuetify
.
theme
.
dark
;
await
this
.
fetchData
();
await
this
.
fetchData
();
},
},
methods
:
{
methods
:
{
closeAddStudentDialog
()
{
this
.
state
.
isAddingStudent
=
false
;
},
fetchDebounced
()
{
fetchDebounced
()
{
// cancel pending call
// cancel pending call
clearTimeout
(
this
.
_timerId
);
clearTimeout
(
this
.
_timerId
);
...
@@ -191,9 +198,8 @@ export default {
...
@@ -191,9 +198,8 @@ export default {
try
{
try
{
const
response
=
await
TrainingService
.
getCourseRegistrationsById
(
const
response
=
await
TrainingService
.
getCourseRegistrationsById
(
this
.
currentCourseId
,
this
.
currentCourseId
,
{
...
this
.
params
,
attendance
:
true
}
{
...
this
.
params
,
attendance
:
true
,
q
:
this
.
search
}
);
);
this
.
listItems
=
this
.
listItems
=
response
.
registrations
?.
map
((
item
)
=>
{
response
.
registrations
?.
map
((
item
)
=>
{
item
.
completed
=
{
value
:
item
.
completed
,
loading
:
false
};
item
.
completed
=
{
value
:
item
.
completed
,
loading
:
false
};
...
@@ -302,33 +308,6 @@ export default {
...
@@ -302,33 +308,6 @@ export default {
await
minimumWait
(
startTime
,
minCheckBoxWaitTime
);
await
minimumWait
(
startTime
,
minCheckBoxWaitTime
);
item
.
completed
.
loading
=
false
;
item
.
completed
.
loading
=
false
;
},
},
async
addStudent
(
student
)
{
if
(
!
student
)
{
student
=
this
.
studentToAdd
;
}
this
.
state
.
isAddingBusy
=
true
;
try
{
await
TrainingService
.
addStudents
(
this
.
currentTrainingCourse
.
id
,
student
);
this
.
studentToAdd
=
student
;
}
catch
(
error
)
{
const
errorMessage
=
error
;
this
.
$store
.
commit
(
SET_ERROR_MESSAGE
,
errorMessage
);
}
finally
{
await
this
.
fetchDebounced
();
this
.
state
.
isAddingBusy
=
false
;
this
.
state
.
isAddingStudent
=
false
;
this
.
$refs
.
userSelect
&&
this
.
$refs
.
userSelect
.
clear
();
}
},
cancelAddStudent
()
{
this
.
studentToAdd
=
null
;
this
.
state
.
isAddingStudent
=
false
;
this
.
state
.
isAddingDuplicate
=
false
;
this
.
$refs
.
userSelect
&&
this
.
$refs
.
userSelect
.
clear
();
},
dateIsValid
(
date
)
{
dateIsValid
(
date
)
{
return
moment
(
date
,
"
YYYY-MM-DD
"
).
isValid
();
return
moment
(
date
,
"
YYYY-MM-DD
"
).
isValid
();
},
},
...
@@ -337,6 +316,12 @@ export default {
...
@@ -337,6 +316,12 @@ export default {
},
},
},
},
watch
:
{
watch
:
{
reload
:
function
(
newVal
,
oldVal
)
{
if
(
isEqual
(
oldVal
,
newVal
))
{
return
;
}
this
.
fetchDebounced
();
},
options
:
{
options
:
{
handler
(
newOptions
,
prevOptions
)
{
handler
(
newOptions
,
prevOptions
)
{
// reduce unnecessary api calls
// reduce unnecessary api calls
...
@@ -407,3 +392,8 @@ export default {
...
@@ -407,3 +392,8 @@ export default {
},
},
};
};
</
script
>
</
script
>
<
style
lang=
"scss"
>
.search
{
width
:
250px
;
}
</
style
>
src/components/TutorialTooltip.vue
View file @
3ad4dc91
...
@@ -134,6 +134,11 @@ export default {
...
@@ -134,6 +134,11 @@ export default {
.dialog-message
{
.dialog-message
{
font-size
:
14px
;
font-size
:
14px
;
font-weight
:
normal
;
font-weight
:
normal
;
font-style
:
normal
;
font-variant
:
normal
;
letter-spacing
:
normal
;
font-family
:
"Open Sans"
,
serif
;
line-height
:
1
.5
;
}
}
.bottom-tooltip-dark
{
.bottom-tooltip-dark
{
...
...
src/components/UserSelect.vue
View file @
3ad4dc91
...
@@ -25,7 +25,6 @@
...
@@ -25,7 +25,6 @@
@
click:prepend=
"setInputElementFocus($refs.userAutocomplete)"
@
click:prepend=
"setInputElementFocus($refs.userAutocomplete)"
class=
"user-select-component"
class=
"user-select-component"
>
>
<ErrorMessage
/>
<template
v-slot:selection=
"data"
>
<template
v-slot:selection=
"data"
>
<v-chip
<v-chip
v-bind=
"data.attr"
v-bind=
"data.attr"
...
@@ -68,7 +67,6 @@
...
@@ -68,7 +67,6 @@
import
UserService
from
"
@/api/services/user
"
;
import
UserService
from
"
@/api/services/user
"
;
import
uniq
from
"
lodash/uniq
"
;
import
uniq
from
"
lodash/uniq
"
;
import
{
setInputElementFocus
}
from
"
@/utils/events
"
;
import
{
setInputElementFocus
}
from
"
@/utils/events
"
;
import
ErrorMessage
from
"
@/components/APIErrorDialog
"
;
import
{
SET_ERROR_MESSAGE
,
SET_ERROR_DIALOG
}
from
"
@/store/mutation-types
"
;
import
{
SET_ERROR_MESSAGE
,
SET_ERROR_DIALOG
}
from
"
@/store/mutation-types
"
;
export
default
{
export
default
{
...
@@ -100,9 +98,6 @@ export default {
...
@@ -100,9 +98,6 @@ export default {
},
},
},
},
},
},
components
:
{
ErrorMessage
,
},
data
:
()
=>
({
data
:
()
=>
({
loading
:
false
,
loading
:
false
,
items
:
[],
items
:
[],
...
...
src/plugins/vuetify.js
View file @
3ad4dc91
...
@@ -68,7 +68,8 @@ export default new Vuetify({
...
@@ -68,7 +68,8 @@ export default new Vuetify({
dark
:
{
dark
:
{
primary
:
"
#BDC931
"
,
primary
:
"
#BDC931
"
,
secondary
:
"
#ffffff
"
,
secondary
:
"
#ffffff
"
,
accent
:
"
#FA8022
"
,
tertiary
:
"
#031322
"
,
accent
:
"
#272727
"
,
success
:
"
#4CAF50
"
,
success
:
"
#4CAF50
"
,
info
:
"
#2196F3
"
,
info
:
"
#2196F3
"
,
warning
:
"
#FB8C00
"
,
warning
:
"
#FB8C00
"
,
...
@@ -77,7 +78,8 @@ export default new Vuetify({
...
@@ -77,7 +78,8 @@ export default new Vuetify({
light
:
{
light
:
{
primary
:
"
#BDC931
"
,
primary
:
"
#BDC931
"
,
secondary
:
"
#031321
"
,
secondary
:
"
#031321
"
,
accent
:
"
#82B1FF
"
,
tertiary
:
"
#ffffff
"
,
accent
:
"
#272727
"
,
error
:
"
#FF5252
"
,
error
:
"
#FF5252
"
,
info
:
"
#2196F3
"
,
info
:
"
#2196F3
"
,
success
:
"
#4CAF50
"
,
success
:
"
#4CAF50
"
,
...
...
src/router/routes.js
View file @
3ad4dc91
import
NotAuthorizedComponent
from
"
@/components/NotAuthorizedComponent
"
;
import
NotAuthorizedComponent
from
"
@/components/NotAuthorizedComponent
"
;
import
NotFoundComponent
from
"
@/components/NotFoundComponent
"
;
import
NotFoundComponent
from
"
@/components/NotFoundComponent
"
;
import
store
from
"
@/store
"
;
import
Permission
from
"
@/config/user-permissions
"
;
import
Permission
from
"
@/config/user-permissions
"
;
export
default
[
export
default
[
{
{
path
:
"
/
"
,
path
:
"
/
"
,
name
:
"
Launchboard
"
,
name
:
"
Launchboard
"
,
component
:
async
()
=>
{
component
:
()
=>
import
(
"
@/views/Home.vue
"
),
const
user
=
store
.
state
.
user
.
user
;
switch
(
user
.
permission
)
{
case
Permission
.
ADMIN
:
return
import
(
"
@/views/admin/LaunchboardAdmin.vue
"
);
case
Permission
.
SUPER_ADMIN
:
return
import
(
"
@/views/super-admin/LaunchboardSuperAdmin.vue
"
);
default
:
return
import
(
"
@/views/Launchboard.vue
"
);
}
},
meta
:
{
meta
:
{
title
:
"
Platform One: Launchboard
"
,
title
:
"
Platform One: Launchboard
"
,
bodyClass
:
"
launchboard-page
"
,
bodyClass
:
"
launchboard-page
"
,
...
...
src/scss/custom.scss
View file @
3ad4dc91
...
@@ -65,10 +65,15 @@ body {
...
@@ -65,10 +65,15 @@ body {
.v-btn
{
.v-btn
{
height
:
40px
;
height
:
40px
;
text-transform
:
uppercase
;
text-transform
:
uppercase
;
border
:
none
!
important
;
&
:not
(
.v-btn--round
)
.v-size--default
{
&
:not
(
.v-btn--round
)
.v-size--default
{
min-width
:
160px
;
min-width
:
160px
;
}
}
&
.primary
{
color
:
$primary-button-text-color
!
important
;
}
}
}
// some text areas have a label too close to the text field
// some text areas have a label too close to the text field
...
@@ -167,59 +172,68 @@ body {
...
@@ -167,59 +172,68 @@ body {
}
}
}
}
.v-btn.no-shadow
{
.filter-input
{
box-shadow
:
none
!
important
;
.v-input
{
}
input
,
.v-btn.no-border
{
.v-select__selections
{
border
:
none
!
important
;
padding-left
:
8px
;
}
color
:
#000000
;
.v-btn
:disabled
{
}
h1
,
.v-input__control
{
h2
,
padding-right
:
8px
;
h3
,
}
h4
{
color
:
rgba
(
255
,
255
,
255
,
0
.3
)
!
important
;
}
}
}
.table-no-link
{
.v-icon
{
color
:
#12b5f6
;
color
:
rgba
(
0
,
0
,
0
,
0
.54
)
!
important
;
&
:hover
{
color
:
lighten
(
#12b5f6
,
10%
)
!
important
;
}
}
}
.theme--dark
{
.v-text-field
{
button
{
padding-top
:
0
;
&
.dark-btn
{
background
:
white
;
background
:
$p1-light-green
!
important
;
border-radius
:
5px
!
important
;
color
:
black
!
important
;
span
.v-btn__content
{
color
:
$p1-light-green
;
color
:
black
!
important
;
}
}
&
.light-btn
{
background
:
white
!
important
;
color
:
black
!
important
;
span
.v-btn__content
{
.
v-input__slot
:
:
before
,
color
:
black
!
important
;
.
v-input__control
::
before
{
}
/* don't display the line unless input is active */
display
:
none
;
}
}
}
}
.v-data-table
a
:hov
er
{
input
:
:
placehold
er
{
text-decoration
:
underline
;
color
:
black
!
important
;
}
}
}
.theme--dark
{
a
.v-btn.secondary
{
a
.v-btn.secondary
{
span
{
span
{
color
:
black
;
color
:
black
;
}
}
}
}
.v-btn
{
/* secondary buttons in dark mode are light, so their text needs to be the secondary-text-color */
&
.secondary
{
color
:
map-get
(
$material-dark
,
"secondary-text-color"
);
}
/* tertiary buttons in dark mode are dark, so their text needs to match the default text color */
&
.tertiary
{
border
:
1px
solid
map-get
(
$material-dark
,
"text-color"
)
!
important
;
}
&
.no-link.v-btn--active
{
&
::before
{
opacity
:
0
.08
;
}
&
:not
(
:hover
)
::before
{
opacity
:
0
;
}
}
}
h1
,
h1
,
h2
,
h2
,
h3
,
h3
,
...
@@ -234,59 +248,6 @@ body {
...
@@ -234,59 +248,6 @@ body {
margin-top
:
65px
;
margin-top
:
65px
;
margin-bottom
:
60px
;
margin-bottom
:
60px
;
}
}
.filter-search
{
div
{
padding
:
0
;
&
::before
{
border-color
:
unset
!
important
;
}
}
label
{
/* design does not have a label or placeholder
for the search bar */
display
:
none
;
}
/* no underline when active */
.v-text-field
>
.v-input__control
>
.v-input__slot
:after
{
width
:
0
!
important
;
}
.v-text-field
{
margin-top
:
-7px
;
background
:
white
;
border-radius
:
5px
!
important
;
color
:
$p1-light-green
;
max-width
:
250px
;
.
v-input__slot
:
:
before
,
.
v-input__control
::
before
{
width
:
97%
;
left
:
3px
;
/* don't display the line unless input is active */
display
:
none
;
}
input
{
color
:
black
;
padding-left
:
5px
;
}
label
{
color
:
black
;
padding-left
:
10px
;
}
.v-icon
{
color
:
black
;
padding-right
:
10px
;
}
}
}
// make scrollbar color light for menus
// make scrollbar color light for menus
.v-menu__content
{
.v-menu__content
{
background-color
:
#000000
;
background-color
:
#000000
;
...
@@ -306,9 +267,11 @@ body {
...
@@ -306,9 +267,11 @@ body {
font-size
:
20px
;
font-size
:
20px
;
}
}
a
.link-to-team
{
a
:not
(
.v-btn--icon
)
{
text-transform
:
capitalize
;
&
.column-link-highlight
,
color
:
$p1-light-green
!
important
;
&
:hover
{
color
:
var
(
--
v-primary-base
)
!
important
;
}
}
}
.v-data-table-header
th
{
.v-data-table-header
th
{
...
@@ -342,40 +305,6 @@ body {
...
@@ -342,40 +305,6 @@ body {
}
}
}
}
.v-btn
{
&
.primary
{
background-color
:
white
!
important
;
border-color
:
white
!
important
;
color
:
black
!
important
;
}
&
.tertiary
{
background
:
transparent
!
important
;
border
:
thin
solid
white
!
important
;
color
:
white
!
important
;
}
&
.v-btn--outlined.secondary--text
{
border-color
:
#e9e9e9
;
}
&
.no-link.v-btn--active
{
&
::before
{
opacity
:
0
.08
;
}
&
:not
(
:hover
)
::before
{
opacity
:
0
;
}
}
&
.limegreen
{
background
:
$p1-light-green
;
color
:
black
!
important
;
border
:
thin
solid
$p1-light-green
!
important
;
}
&
.not-operable
{
background-color
:
rgba
(
255
,
255
,
255
,
0
.12
)
!
important
;
border
:
thin
solid
transparent
!
important
;
pointer-events
:
none
!
important
;
}
}
.v-dialog
{
.v-dialog
{
label
.available-seats-label
{
label
.available-seats-label
{
color
:
white
;
color
:
white
;
...
@@ -392,91 +321,12 @@ body {
...
@@ -392,91 +321,12 @@ body {
}
}
}
}
.theme--light
{
.theme--light
{
.filter-search
{
div
{
padding
:
0
;
&
::before
{
border-color
:
unset
!
important
;
}
}
label
{
/* design does not have a label or placeholder
for the search bar */
display
:
none
;
}
/* no underline when active */
.v-text-field
>
.v-input__control
>
.v-input__slot
:after
{
width
:
0
!
important
;
}
.v-text-field
{
margin-top
:
-7px
;
background
:
white
;
border-radius
:
5px
!
important
;
color
:
$p1-light-green
;
max-width
:
250px
;
.
v-input__slot
:
:
before
,
.
v-input__control
::
before
{
width
:
0
!
important
;
display
:
none
;
}
.
v-input__control
:
:
after
{
width
:
0
!
important
;
display
:
none
;
}
input
{
color
:
black
;
padding-left
:
5px
;
}
label
{
color
:
black
;
padding-left
:
10px
;
}
.v-icon
{
color
:
black
;
padding-right
:
10px
;
}
}
}
a
.v-btn.secondary
{
a
.v-btn.secondary
{
span
{
span
{
color
:
white
;
color
:
white
;
}
}
}
}
button
{
&
.table-action-btn
{
background
:
#272727
!
important
;
color
:
white
;
}
&
.dark-btn
{
background
:
rgb
(
3
,
19
,
33
)
!
important
;
color
:
white
!
important
;
span
.v-btn__content
{
color
:
white
!
important
;
}
}
&
.light-btn
{
background
:
white
!
important
;
color
:
black
!
important
;
span
.v-btn__content
{
color
:
black
!
important
;
}
}
}
a
{
a
{
color
:
black
!
important
;
color
:
black
!
important
;
}
}
...
@@ -485,10 +335,6 @@ body {
...
@@ -485,10 +335,6 @@ body {
text-decoration
:
underline
;
text-decoration
:
underline
;
}
}
.dark-button
{
color
:
white
!
important
;
}
.v-application
a
{
.v-application
a
{
color
:
#021421
!
important
;
color
:
#021421
!
important
;
}
}
...
@@ -501,11 +347,6 @@ body {
...
@@ -501,11 +347,6 @@ body {
color
:
map-get
(
$material-light
,
"text-color"
);
color
:
map-get
(
$material-light
,
"text-color"
);
}
}
a
.link-to-team
{
text-transform
:
capitalize
;
color
:
#0d6b90
!
important
;
}
.v-expansion-panel-header
{
.v-expansion-panel-header
{
background-color
:
#f8f8f8
;
background-color
:
#f8f8f8
;
}
}
...
@@ -595,8 +436,14 @@ body {
...
@@ -595,8 +436,14 @@ body {
}
}
.v-data-table
{
.v-data-table
{
a
:hover:not
(
.v-btn--icon
)
{
text-decoration
:
underline
;
}
td
{
td
{
border-bottom
:
none
!
important
;
border-bottom
:
none
!
important
;
padding-top
:
8px
!
important
;
padding-bottom
:
8px
!
important
;
}
}
// update paging footer to fit on one row in mobile
// update paging footer to fit on one row in mobile
...
@@ -642,12 +489,6 @@ body {
...
@@ -642,12 +489,6 @@ body {
}
}
.v-btn
{
.v-btn
{
&
.secondary
{
color
:
map-get
(
$material-light
,
"background-accent-2"
);
}
&
.v-btn--outlined.secondary--text
{
border-color
:
#e9e9e9
;
}
&
.no-link.v-btn--active
{
&
.no-link.v-btn--active
{
&
::before
{
&
::before
{
opacity
:
0
.08
;
opacity
:
0
.08
;
...
...
src/scss/variables.scss
View file @
3ad4dc91
...
@@ -3,8 +3,6 @@ $bottom-bg-color: #04243a;
...
@@ -3,8 +3,6 @@ $bottom-bg-color: #04243a;
$text-color
:
#ffffff
;
$text-color
:
#ffffff
;
$dark-bg-color
:
#002743
;
$dark-bg-color
:
#002743
;
$button-text-color
:
#000000
;
$gradient-alpha
:
#000000
00
;
$gradient-alpha
:
#000000
00
;
$p1-light-green
:
#bdc931
;
$p1-light-green
:
#bdc931
;
...
@@ -17,9 +15,6 @@ $bottom-bg: #031727;
...
@@ -17,9 +15,6 @@ $bottom-bg: #031727;
$link-color
:
#ffffff
;
$link-color
:
#ffffff
;
$link-hover-color
:
#efefef
;
$link-hover-color
:
#efefef
;
$button-border-color
:
#002743
;
$button-border
:
0
.5px
solid
$button-border-color
!
important
;
$table-row-even-bg
:
#15283a
;
$table-row-even-bg
:
#15283a
;
$table-row-odd-bg
:
#010e19
;
$table-row-odd-bg
:
#010e19
;
...
@@ -30,6 +25,7 @@ $table-row-odd-bg-light: #fbfbfb;
...
@@ -30,6 +25,7 @@ $table-row-odd-bg-light: #fbfbfb;
$body-font-family
:
"Open Sans"
,
serif
;
$body-font-family
:
"Open Sans"
,
serif
;
$border-radius-root
:
4px
;
$border-radius-root
:
4px
;
$font-size-root
:
16px
;
$font-size-root
:
16px
;
$primary-button-text-color
:
#000000
;
// Variables must come before the import
// Variables must come before the import
$btn-font-weight
:
600
;
$btn-font-weight
:
600
;
...
@@ -54,10 +50,12 @@ $material-light: (
...
@@ -54,10 +50,12 @@ $material-light: (
background-accent-3
:
#efefef
,
background-accent-3
:
#efefef
,
primary
:
#031322
,
primary
:
#031322
,
text-color
:
#000000
,
text-color
:
#000000
,
secondary-text-color
:
#ffffff
,
);
);
$material-dark
:
(
$material-dark
:
(
background
:
#04243a
,
background
:
#04243a
,
background-accent-1
:
#15283a
,
background-accent-1
:
#15283a
,
background-accent-2
:
#031322
,
background-accent-2
:
#031322
,
text-color
:
#ffffff
,
text-color
:
#ffffff
,
secondary-text-color
:
#000000
,
);
);
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment