Msp dashboard: Add syncing overlay. (#23311)

Related to: https://github.com/fleetdm/confidential/issues/8602

Changes:
- Added a syncing overlay when the dashboard gathers an updated list of
software, profiles, and scripts from a Fleet instance.
This commit is contained in:
Eric 2024-10-28 17:24:21 -05:00 committed by GitHub
parent 6e9955d7c7
commit 48578a0a32
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 131 additions and 7 deletions

View file

@ -0,0 +1,103 @@
/**
* <ajax-overlay>
* -----------------------------------------------------------------------------
*
* @type {Component}
*
* --- SLOTS: ---
* N/A
*
* --- EVENTS EMITTED: ---
* N/A
*
* -----------------------------------------------------------------------------
*/
parasails.registerComponent('ajaxOverlay', {
// ╔═╗╦ ╦╔╗ ╦ ╦╔═╗ ╔═╗╦═╗╔═╗╔═╗╔═╗
// ╠═╝║ ║╠╩╗║ ║║ ╠═╝╠╦╝║ ║╠═╝╚═╗
// ╩ ╚═╝╚═╝╩═╝╩╚═╝ ╩ ╩╚═╚═╝╩ ╚═╝
props: [
'syncing',
'syncingMessage'
],
// ╦╔╗╔╦╔╦╗╦╔═╗╦ ╦╔╗╔╔╦╗╔═╗╦═╗╔╗╔╔═╗╦ ╔═╗╔╦╗╔═╗╔╦╗╔═╗
// ║║║║║ ║ ║╠═╣║ ║║║║ ║ ║╣ ╠╦╝║║║╠═╣║ ╚═╗ ║ ╠═╣ ║ ║╣
// ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╩╝╚╝ ╩ ╚═╝╩╚═╝╚╝╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝
data: function () {
return {
//…
};
},
beforeMount: function() {
//…
},
// ╦ ╦╔╦╗╔╦╗╦
// ╠═╣ ║ ║║║║
// ╩ ╩ ╩ ╩ ╩╩═╝
template: `
<div style="top: 0; left: 0; background-color: rgba(255,255,255,0.75); z-index: 1000;" class="position-fixed w-100 h-100" :class="syncing? '' : 'd-none'">
<div class="row h-100">
<div class="col h-100"></div>
<div class="col-6 col-md-4 h-100">
<div class="d-flex flex-column h-100 justify-content-center">
<div class="py-5 text-center">
<h2 purpose="syncing-message" class="text-dark" v-if="syncingMessage">{{syncingMessage}}</h2>
<span purpose="loading-indicator">
<span class="loading-dot dot1"></span>
<span class="loading-dot dot2"></span>
<span class="loading-dot dot3"></span>
<span class="loading-dot dot4"></span>
</span>
</div>
</div>
</div>
<div class="col h-100"></div>
</div>
</div>
`,
// ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗
// ║ ║╠╣ ║╣ ║ ╚╦╝║ ║ ║╣
// ╩═╝╩╚ ╚═╝╚═╝ ╩ ╚═╝╩═╝╚═╝
mounted: async function () {
//…
},
beforeDestroy: function() {
//…
},
// ╦╔╗╔╔╦╗╔═╗╦═╗╔═╗╔═╗╔╦╗╦╔═╗╔╗╔╔═╗
// ║║║║ ║ ║╣ ╠╦╝╠═╣║ ║ ║║ ║║║║╚═╗
// ╩╝╚╝ ╩ ╚═╝╩╚═╩ ╩╚═╝ ╩ ╩╚═╝╝╚╝╚═╝
methods: {
// ╦╔╗╔╔╦╗╔═╗╦═╗╔╗╔╔═╗╦ ╔═╗╦ ╦╔═╗╔╗╔╔╦╗ ╦ ╦╔═╗╔╗╔╔╦╗╦ ╔═╗╦═╗╔═╗
// ║║║║ ║ ║╣ ╠╦╝║║║╠═╣║ ║╣ ╚╗╔╝║╣ ║║║ ║ ╠═╣╠═╣║║║ ║║║ ║╣ ╠╦╝╚═╗
// ╩╝╚╝ ╩ ╚═╝╩╚═╝╚╝╩ ╩╩═╝ ╚═╝ ╚╝ ╚═╝╝╚╝ ╩ ╩ ╩╩ ╩╝╚╝═╩╝╩═╝╚═╝╩╚═╚═╝
//…
// ╔═╗╦ ╦╔╗ ╦ ╦╔═╗ ╔╦╗╔═╗╔╦╗╦ ╦╔═╗╔╦╗╔═╗
// ╠═╝║ ║╠╩╗║ ║║ ║║║║╣ ║ ╠═╣║ ║ ║║╚═╗
// ╩ ╚═╝╚═╝╩═╝╩╚═╝ ╩ ╩╚═╝ ╩ ╩ ╩╚═╝═╩╝╚═╝
// > Public methods are rarely exposed by Vue components, but sometimes they
// > are an important escape hatch. They are callable via something like
// > `this.$refs.ajaxOverlay.doSomething())`, and, by convention, are always
// > prefixed with "do".
// N/A
// ╔═╗╦═╗╦╦ ╦╔═╗╔╦╗╔═╗ ╔╦╗╔═╗╔╦╗╦ ╦╔═╗╔╦╗╔═╗
// ╠═╝╠╦╝║╚╗╔╝╠═╣ ║ ║╣ ║║║║╣ ║ ╠═╣║ ║ ║║╚═╗
// ╩ ╩╚═╩ ╚╝ ╩ ╩ ╩ ╚═╝ ╩ ╩╚═╝ ╩ ╩ ╩╚═╝═╩╝╚═╝
//…
}
});

View file

@ -23,6 +23,8 @@ parasails.registerPage('profiles', {
profileToEdit: {},
cloudError: '',
newProfile: undefined,
syncingMessage: '',
overlaySyncing: false,
},
// ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗
@ -118,10 +120,11 @@ parasails.registerPage('profiles', {
await this._getProfiles();
},
_getProfiles: async function() {
this.syncing = true;
this.overlaySyncing = true;
this.syncingMessage = 'Gathering profiles';
let newProfilesInformation = await Cloud.getProfiles();
this.profiles = newProfilesInformation;
this.syncing = false;
this.overlaySyncing = false;
await this.changeTeamFilter();
}
}

View file

@ -23,6 +23,8 @@ parasails.registerPage('scripts', {
profileToEdit: {},
cloudError: '',
newScript: undefined,
syncingMessage: '',
overlaySyncing: '',
},
// ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗
@ -110,10 +112,11 @@ parasails.registerPage('scripts', {
await this._getScripts();
},
_getScripts: async function() {
this.syncing = true;
this.overlaySyncing = true;
this.syncingMessage = 'Gathering scripts';
let newScriptsInformation = await Cloud.getScripts();
this.scripts = newScriptsInformation;
this.syncing = false;
this.overlaySyncing = false;
await this.changeTeamFilter();
}
}

View file

@ -25,7 +25,8 @@ parasails.registerPage('software', {
newSoftware: undefined,
showAdvancedOptions: false,
newSoftwareFilename: undefined,
syncingMessage: '',
overlaySyncing: false,
},
// ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗
@ -136,10 +137,11 @@ parasails.registerPage('software', {
}
},
_getSoftware: async function() {
this.syncing = true;
this.overlaySyncing = true;
this.syncingMessage = 'Gathering software';
let newSoftwareInformation = await Cloud.getSoftware();
this.software = newSoftwareInformation;
this.syncing = false;
this.overlaySyncing = false;
await this.changeTeamFilter();
}
}

View file

@ -0,0 +1,8 @@
/**
* <ajax-overlay>
*/
[parasails-component='ajax-overlay'] {
[purpose='loading-indicator'] {
.loader(@brand);
}
}

View file

@ -19,6 +19,7 @@
// Per-component styles
@import 'components/stripe-card-element.component.less';
@import 'components/ajax-button.component.less';
@import 'components/ajax-overlay.component.less';
@import 'components/modal.component.less';
@import 'components/cloud-error.component.less';
@import 'components/multifield.component.less';

View file

@ -143,6 +143,7 @@
<script src="/js/components/ace-editor.component.js"></script>
<script src="/js/components/ajax-button.component.js"></script>
<script src="/js/components/ajax-form.component.js"></script>
<script src="/js/components/ajax-overlay.component.js"></script>
<script src="/js/components/cloud-error.component.js"></script>
<script src="/js/components/file-upload.component.js"></script>
<script src="/js/components/js-timestamp.component.js"></script>

View file

@ -150,5 +150,6 @@
</ajax-form>
</div>
</modal>
<ajax-overlay :syncing-message="syncingMessage" :syncing="overlaySyncing"></ajax-overlay>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>

View file

@ -160,5 +160,6 @@
</ajax-form>
</div>
</modal>
<ajax-overlay :syncing-message="syncingMessage" :syncing="overlaySyncing"></ajax-overlay>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>

View file

@ -196,5 +196,6 @@
</ajax-form>
</div>
</modal>
<ajax-overlay :syncing-message="syncingMessage" :syncing="overlaySyncing"></ajax-overlay>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>