Skip to content

Commit 1600b27

Browse files
authored
Lock UI when Job in progress (#42)
* Lock install & uninstall buttons if composer busy * Fix redirect after job delete
1 parent 4c421fa commit 1600b27

File tree

9 files changed

+155
-162
lines changed

9 files changed

+155
-162
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ All notable changes to `cybercog/laravel-paket` will be documented in this file.
88

99
- ([#39]) Add jobs deletion
1010

11+
### Fixed
12+
13+
- ([#42]) Lock UI when Job in progress
14+
1115
## [1.3.0]
1216

1317
### Added
@@ -47,6 +51,7 @@ All notable changes to `cybercog/laravel-paket` will be documented in this file.
4751
[1.2.0]: https://github.com/cybercog/laravel-paket/compare/1.1.0...1.2.0
4852
[1.1.0]: https://github.com/cybercog/laravel-paket/compare/1.0.0...1.1.0
4953

54+
[#42]: https://github.com/cybercog/laravel-paket/pull/42
5055
[#35]: https://github.com/cybercog/laravel-paket/pull/35
5156
[#33]: https://github.com/cybercog/laravel-paket/pull/33
5257
[#32]: https://github.com/cybercog/laravel-paket/pull/32

resources/js/components/Job/OptionsMenu.vue

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,7 @@
6767
title: 'Job Deleted!',
6868
});
6969
70-
const jobsListUrl = this.$store.getters.getUrl('/jobs');
71-
const currentUrl = window.location.href;
72-
if (currentUrl !== jobsListUrl) {
73-
window.location.href = jobsListUrl;
74-
}
70+
await this.$router.replace('/jobs');
7571
}
7672
},
7773
},

resources/js/components/Paket.vue

Lines changed: 30 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,27 @@
22
<div class="flex align-top">
33
<img
44
class="w-10 h-10 rounded mr-4 bg-gray-700 p-1"
5-
:style="`background-color: ${this.iconBg}`"
6-
:src="this.icon"
5+
:style="`background-color: ${paket.iconBg || '#4a5568'}`"
6+
:src="paket.icon"
77
alt=""
88
/>
99
<div>
10-
<h4 class="text-gray-900 font-mono" v-text="title"></h4>
11-
<div class="text-gray-600 font-mono text-xs" v-text="description"></div>
10+
<h4 class="text-gray-900 font-mono" v-text="paket.title"></h4>
11+
<div class="text-gray-600 font-mono text-xs" v-text="paket.description"></div>
1212
</div>
1313

1414
<div class="ml-auto text-right">
1515
<div v-if="isInstalled()">
1616
<uninstall-button
17-
:requirement="{name: this.name, isDevelopment: this.isDevelopment}"
17+
:requirement="getRequirement()"
1818
></uninstall-button>
1919
<div class="mt-2">
2020
<span class="bg-gray-200 border-b-2 border-gray-400 px-2 py-1 text-sm font-semibold font-mono tracking-wide text-gray-700" v-text="getVersion()"></span>
2121
</div>
2222
</div>
2323
<div v-if="!isInstalled()">
2424
<install-button
25-
:requirement="{name: this.name, isDevelopment: this.isDevelopment}"
25+
:requirement="getRequirement()"
2626
></install-button>
2727
</div>
2828
</div>
@@ -40,41 +40,30 @@
4040
},
4141
4242
props: {
43-
name: {
44-
type: String,
43+
paket: {
44+
type: Object,
4545
required: true,
46+
}
47+
},
48+
49+
methods: {
50+
getRequirement() {
51+
return {
52+
name: this.paket.name,
53+
isDevelopment: this.paket.isDevelopment || false,
54+
};
4655
},
47-
title: {
48-
type: String,
49-
required: false,
50-
},
51-
description: {
52-
type: String,
53-
required: false,
54-
},
55-
icon: {
56-
type: String,
57-
required: false,
58-
},
59-
iconBg: {
60-
type: String,
61-
required: false,
62-
default: '#4a5568',
63-
},
64-
isDevelopment: {
65-
type: Boolean,
66-
required: false,
67-
default: false,
56+
57+
hasActiveJobs() {
58+
return this.$store.getters.getActiveJobs().length > 0;
6859
},
69-
},
7060
71-
mounted() {
72-
this.fetchData();
73-
},
61+
isInProgress() {
62+
const jobs = this.$store.getters.getRequirementActiveJobs(
63+
this.getRequirement()
64+
);
7465
75-
methods: {
76-
async fetchData() {
77-
await this.$store.dispatch('collectRequirements');
66+
return jobs.length > 0;
7867
},
7968
8069
isInstalled() {
@@ -83,23 +72,24 @@
8372
8473
getVersion() {
8574
let version;
75+
const name = this.paket.name;
8676
87-
version = this.findRequirementVersion(this.getRequirements('roots', 'essential'), this.name);
77+
version = this.findRequirementVersion(this.getRequirements('roots', 'essential'), name);
8878
if (version !== null) {
8979
return version;
9080
}
9181
92-
version = this.findRequirementVersion(this.getRequirements('roots', 'dev'), this.name);
82+
version = this.findRequirementVersion(this.getRequirements('roots', 'dev'), name);
9383
if (version !== null) {
9484
return version;
9585
}
9686
97-
version = this.findRequirementVersion(this.getRequirements('dependencies', 'essential'), this.name);
87+
version = this.findRequirementVersion(this.getRequirements('dependencies', 'essential'), name);
9888
if (version !== null) {
9989
return version;
10090
}
10191
102-
version = this.findRequirementVersion(this.getRequirements('dependencies', 'dev'), this.name);
92+
version = this.findRequirementVersion(this.getRequirements('dependencies', 'dev'), name);
10393
if (version !== null) {
10494
return version;
10595
}

resources/js/components/Requirement/InstallButton.vue

Lines changed: 17 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<template>
22
<button
33
type="button"
4-
:class="getClasses()"
5-
:disabled="isFormDisabled()"
6-
v-text="buttonText"
4+
:class="getClass()"
5+
:disabled="isDisabled()"
6+
v-text="getText()"
77
v-on:click="install()"
88
></button>
99
</template>
@@ -17,64 +17,41 @@
1717
},
1818
},
1919
20-
data() {
21-
return {
22-
buttonText: 'Install',
23-
isInvoker: false,
24-
};
25-
},
26-
2720
methods: {
2821
async install() {
29-
this.disableForm();
30-
3122
try {
32-
this.alertInfo({
33-
title: `Installing\n${this.requirement.name}`,
34-
showConfirmButton: false,
35-
});
36-
3723
await this.$store.dispatch('postJobs', {
3824
type: 'RequirementInstall',
3925
requirement: this.requirement,
4026
});
41-
42-
this.alertSuccess({
43-
title: `Installed\n${this.requirement.name}`,
44-
});
4527
} catch (exception) {
4628
this.alertError(exception);
4729
}
48-
49-
this.enableForm();
5030
},
5131
52-
getClasses() {
32+
getClass() {
33+
const classes = 'font-semibold px-2 py-1 text-xs rounded focus:outline-none focus:shadow-outline uppercase';
5334
const activeClasses = 'bg-indigo-600 hover:bg-indigo-800 text-indigo-100 hover:text-white';
54-
const invokerClasses = 'bg-indigo-800 text-white';
55-
const othersClasses = 'bg-gray-400 text-black';
35+
const runningClasses = 'bg-indigo-800 text-white';
36+
const lockedClasses = 'bg-gray-400 text-black';
5637
57-
const inactiveClasses = this.isInvoker ? invokerClasses : othersClasses;
58-
59-
const classes = 'font-semibold px-2 py-1 text-xs rounded focus:outline-none focus:shadow-outline uppercase';
38+
const disabledClasses = this.isInProgress() ? runningClasses : lockedClasses;
6039
61-
return `${classes} ${this.isFormDisabled() ? inactiveClasses : activeClasses}`;
40+
return `${classes} ${this.isDisabled() ? disabledClasses : activeClasses}`;
6241
},
6342
64-
isFormDisabled() {
65-
return this.$store.state.isComposerBusy;
43+
getText() {
44+
return this.isInProgress() ? 'Installing' : 'Install';
6645
},
6746
68-
disableForm() {
69-
this.buttonText = 'Installing';
70-
this.isInvoker = true;
71-
this.$store.commit('runComposer');
47+
isDisabled() {
48+
return this.$store.state.isComposerBusy
49+
|| this.$store.getters.getActiveJobs().length > 0;
7250
},
7351
74-
enableForm() {
75-
this.buttonText = 'Install';
76-
this.isInvoker = false;
77-
this.$store.commit('stopComposer');
52+
isInProgress() {
53+
return this.$store.getters.isProcessingRequirement(this.requirement)
54+
|| this.$store.getters.getRequirementActiveJobs(this.requirement).length > 0;
7855
},
7956
},
8057
}

resources/js/components/Requirement/InstallForm.vue

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22
<div class="flex">
33
<input
44
type="text"
5-
class="shadow appearance-none border rounded-l w-full py-2 px-3 text-gray-900 placeholder-gray-700 leading-tight focus:outline-none focus:shadow-outline"
6-
:readonly="isFormDisabled()"
5+
:class="getInputClass()"
6+
:readonly="isDisabled()"
77
v-model="command"
88
v-on:keyup.enter="install()"
99
placeholder="Type in vendor/package OR composer require vendor/package"
1010
/>
1111
<button
1212
type="submit"
13-
class="bg-indigo-600 hover:bg-indigo-800 text-indigo-100 hover:text-white font-semibold py-2 px-4 rounded-r uppercase"
14-
:disabled="isFormDisabled()"
15-
v-text="buttonText"
13+
:class="getButtonClass()"
14+
:disabled="isDisabled()"
15+
v-text="getButtonText()"
1616
v-on:click="install()"
1717
>
1818
Install
@@ -31,56 +31,70 @@
3131
version: null,
3232
isDevelopment: false,
3333
},
34+
isInputInvalid: false,
35+
isProcessing: false,
3436
};
3537
},
3638
3739
methods: {
3840
async install() {
41+
this.sanitizeInput();
42+
3943
if (this.command === '') {
40-
this.alertWarning({
41-
title: 'Field `command` is required!',
42-
});
44+
this.isInputInvalid = true;
4345
return;
4446
}
47+
this.isInputInvalid = false;
4548
46-
this.disableForm();
47-
this.sanitizeInput();
4849
this.parseCommand();
4950
5051
try {
51-
this.alertInfo({
52-
title: `Installing\n${this.requirement.name}`,
53-
showConfirmButton: false,
54-
});
55-
5652
await this.$store.dispatch('postJobs', {
5753
type: 'RequirementInstall',
5854
requirement: this.requirement,
5955
});
60-
61-
this.alertSuccess({
62-
title: `Installed\n${this.requirement.name}`,
63-
});
6456
} catch (exception) {
6557
this.alertError(exception);
6658
}
6759
6860
this.forgetInput();
69-
this.enableForm();
7061
},
7162
72-
isFormDisabled() {
73-
return this.$store.state.isComposerBusy;
63+
isDisabled() {
64+
return this.$store.state.isComposerBusy
65+
|| this.$store.getters.getActiveJobs().length > 0;
7466
},
7567
76-
disableForm() {
77-
this.buttonText = 'Installing';
78-
this.$store.commit('runComposer');
68+
isInProgress() {
69+
return this.$store.getters.isProcessingRequirement(this.requirement)
70+
|| this.$store.getters.getRequirementActiveJobs(this.requirement).length > 0;
71+
},
72+
73+
getInputClass() {
74+
const classes = 'shadow appearance-none rounded-l w-full py-2 px-3 text-gray-900 placeholder-gray-700 leading-tight focus:outline-none focus:shadow-outline border-2 border-r-0';
75+
const runningClasses = 'border-indigo-700 bg-indigo-100';
76+
const invalidClass = 'border-red-600 bg-red-100 placeholder-red-900';
77+
78+
if (this.isInProgress()) {
79+
return `${classes} ${runningClasses}`;
80+
}
81+
82+
return `${classes} ${this.isInputInvalid ? invalidClass : ''}`;
83+
},
84+
85+
getButtonClass() {
86+
const classes = 'font-semibold py-2 px-4 rounded-r uppercase focus:outline-none focus:shadow-outline';
87+
const activeClasses = 'bg-indigo-600 hover:bg-indigo-800 text-indigo-100 hover:text-white';
88+
const runningClasses = 'bg-indigo-800 text-white';
89+
const lockedClasses = 'bg-gray-400 text-black';
90+
91+
const disabledClasses = this.isInProgress() ? runningClasses : lockedClasses;
92+
93+
return `${classes} ${this.isDisabled() ? disabledClasses : activeClasses}`;
7994
},
8095
81-
enableForm() {
82-
this.buttonText = 'Install';
83-
this.$store.commit('stopComposer');
96+
getButtonText() {
97+
return this.isInProgress() ? 'Installing' : 'Install';
8498
},
8599
86100
sanitizeInput() {

0 commit comments

Comments
 (0)