Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Persist state of lock store between tabs #531

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
1,048 changes: 972 additions & 76 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"markdown-it": "^12.0.6",
"marked": "^4.0.10",
"nouislider": "^15.5.0",
"pinia-plugin-persistedstate": "^4.2.0",
"ramp-config-editor_editeur-config-pcar": "^3.6.0",
"ramp-pcar": "^4.10.2",
"ramp-storylines_demo-scenarios-pcar": "^3.2.9",
Expand Down
1 change: 1 addition & 0 deletions src/components/editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,7 @@ export default class EditorV extends Vue {
return slide ?? JSON.parse(JSON.stringify(this.defaultBlankSlide));
});
const lockStore = useLockStore();

setTimeout(() => {
const routeData = this.$router.resolve({
name: 'preview',
Expand Down
4 changes: 4 additions & 0 deletions src/components/metadata-editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,7 @@ export default class MetadataEditorV extends Vue {
// session was extended from the preview tab, need to handle in editor tab
const msg = e.data;
if (msg.action === 'extend') {
console.log('metadata - received extend message from preview');
this.$vfm.close('confirm-extend-session-editor');
this.extendSession(msg.showPopup);
}
Expand All @@ -861,6 +862,7 @@ export default class MetadataEditorV extends Vue {
document.onmousemove = () => undefined;
document.onkeydown = () => undefined;
this.$vfm.open(`confirm-extend-session-editor`);
console.log('metadata - broadcast confirm message to preview');
this.lockStore.broadcast?.postMessage({ action: 'confirm', value: this.lockStore.timeRemaining });
}, this.lockStore.timeRemaining * 1000 - warnTime * 60 * 1000);
// After the timer has run out, if the session was not extended, go back to the landing page (which will unlock the storyline).
Expand All @@ -886,6 +888,7 @@ export default class MetadataEditorV extends Vue {
clearTimeout(this.lockStore.endTimeout);
clearTimeout(this.lockStore.confirmationTimeout);
if (showPopup) {
console.log('metadata - broadcasting extend message to preview');
Message.success(this.$t('editor.session.extended'));
this.lockStore.broadcast?.postMessage({ action: 'extend' });
}
Expand Down Expand Up @@ -1104,6 +1107,7 @@ export default class MetadataEditorV extends Vue {
// session was extended from the preview tab, need to handle in editor tab
const msg = e.data;
if (msg.action === 'extend') {
console.log('metadata - received extend message from preview');
this.$vfm.close('confirm-extend-session-editor');
this.extendSession(msg.showPopup);
}
Expand Down
127 changes: 66 additions & 61 deletions src/components/preview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,14 @@ export default class StoryPreviewV extends Vue {
totalTime = import.meta.env.VITE_APP_CURR_ENV ? Number(import.meta.env.VITE_SESSION_END) : 30;

extendSession(showPopup?: boolean): void {
if (!this.savedProduct) {
this.broadcast?.postMessage({ action: 'extend', showPopup });
}
// if (!this.savedProduct) {
console.log('preview - sending extend message to metadata');
this.broadcast?.postMessage({ action: 'extend', showPopup });
// }
}

async mounted() {
console.log('preview - mounted');
this.uid = this.$route.params.uid as string;
this.lang = this.$route.params.lang as string;
const lockStore = useLockStore();
Expand All @@ -128,63 +130,6 @@ export default class StoryPreviewV extends Vue {
this.config = JSON.parse(JSON.stringify(window.props.configs[this.lang]));
this.configs = window.props.configs;
this.configFileStructure = window.props.configFileStructure;
// this broadcast channel will be used to communicate regarding sessions with the main editor tab
this.broadcast = new BroadcastChannel(window.props.secret);
this.broadcast.onmessage = (e) => {
const msg = e.data;
if (msg.action === 'confirm') {
// First, remove inactivity event listeners, otherwise moving the mouse will extend the session!.
document.onmousemove = () => undefined;
document.onkeydown = () => undefined;
// main tab says show confirmation modal
this.lockStore.resetSession(msg.value);
this.$vfm.open(`confirm-extend-session-preview`);
} else if (msg.action === 'close') {
// main tab says close modal
this.$vfm.close(`confirm-extend-session-preview`);
} else if (msg.action === 'extend') {
// main tab says extend the session
Message.success(this.$t('editor.session.extended'));
this.$vfm.close(`confirm-extend-session-preview`);
// Now add back event listeners to detect inactivity
document.onmousemove = () => this.extendSession();
document.onkeydown = () => this.extendSession();
} else if (msg.action === 'saving') {
// main editor tab is saving
// disable session extend on activity
this.$vfm.close(`confirm-extend-session-preview`);
document.onmousemove = () => undefined;
document.onkeydown = () => undefined;
} else if (msg.action === 'saved') {
// main editor tab is done saving
// re-enable session extend on activity
document.onmousemove = () => this.extendSession();
document.onkeydown = () => this.extendSession();
} else {
// main tab says end the session
// we display the toast to say the session has ended in the other tab
// but keep showing the preview since technically that does not require any locks
this.$vfm.close('confirm-extend-session-preview');
Message.error(this.$t('editor.session.ended'));
// Remove inactivity listeners since session has expired.
document.onmousemove = () => undefined;
document.onkeydown = () => undefined;
}
};
const minsRemaining = window.props.timeRemaining / 60;
const warnMins = import.meta.env.VITE_APP_CURR_ENV ? Number(import.meta.env.VITE_SESSION_WARN) : 5;
if (minsRemaining <= warnMins) {
// Preview tab was opened with < the amount of time remaining in a session timeout that we have to show the warning
// Therefore, display warning immediately and do not track activity.
document.onmousemove = () => undefined;
document.onkeydown = () => undefined;
this.lockStore.resetSession(minsRemaining * 60);
this.$vfm.open(`confirm-extend-session-preview`);
} else {
// Extend the session in the main editor tab if the user does something in the preview tab
document.onmousemove = () => this.extendSession();
document.onkeydown = () => this.extendSession();
}
this.loadStatus = 'loaded';
} else {
this.savedProduct = true;
Expand Down Expand Up @@ -252,13 +197,72 @@ export default class StoryPreviewV extends Vue {
fetch(this.apiUrl + `/retrieveMessages`).then((res: any) => {
axios
.post(import.meta.env.VITE_APP_NET_API_URL + '/api/log/create', {
messages: res.data.messages
messages: res.data?.messages
})
.catch((error: AxiosError) => console.log(error.response || error));
});
});
}

// This broadcast channel will be used to communicate regarding sessions with the main editor tab
this.broadcast = new BroadcastChannel(lockStore.secret); // perhaps more than one of these are being created on lang change
this.broadcast.onmessage = (e) => {
console.log('preview - message received from metadata');
const msg = e.data;
if (msg.action === 'confirm') {
// First, remove inactivity event listeners, otherwise moving the mouse will extend the session!.
document.onmousemove = () => undefined;
document.onkeydown = () => undefined;
// main tab says show confirmation modal
this.lockStore.resetSession(msg.value);
this.$vfm.open(`confirm-extend-session-preview`);
} else if (msg.action === 'close') {
// main tab says close modal
this.$vfm.close(`confirm-extend-session-preview`);
} else if (msg.action === 'extend') {
// main tab says extend the session
Message.success(this.$t('editor.session.extended'));
this.$vfm.close(`confirm-extend-session-preview`);
// Now add back event listeners to detect inactivity
document.onmousemove = () => this.extendSession();
document.onkeydown = () => this.extendSession();
} else if (msg.action === 'saving') {
// main editor tab is saving
// disable session extend on activity
this.$vfm.close(`confirm-extend-session-preview`);
document.onmousemove = () => undefined;
document.onkeydown = () => undefined;
} else if (msg.action === 'saved') {
// main editor tab is done saving
// re-enable session extend on activity
document.onmousemove = () => this.extendSession();
document.onkeydown = () => this.extendSession();
} else {
// main tab says end the session
// we display the toast to say the session has ended in the other tab
// but keep showing the preview since technically that does not require any locks
this.$vfm.close('confirm-extend-session-preview');
Message.error(this.$t('editor.session.ended'));
// Remove inactivity listeners since session has expired.
document.onmousemove = () => undefined;
document.onkeydown = () => undefined;
}
};
const minsRemaining = lockStore.timeRemaining / 60;
const warnMins = import.meta.env.VITE_APP_CURR_ENV ? Number(import.meta.env.VITE_SESSION_WARN) : 5;
if (minsRemaining <= warnMins) {
// Preview tab was opened with < the amount of time remaining in a session timeout that we have to show the warning
// Therefore, display warning immediately and do not track activity.
document.onmousemove = () => undefined;
document.onkeydown = () => undefined;
this.lockStore.resetSession(minsRemaining * 60);
this.$vfm.open(`confirm-extend-session-preview`);
} else {
// Extend the session in the main editor tab if the user does something in the preview tab
document.onmousemove = () => this.extendSession();
document.onkeydown = () => this.extendSession();
}

// Purge undefined slides from configs
if (this.config) {
this.config.slides = this.config.slides.filter((slide) => slide && Object.keys(slide).length);
Expand All @@ -278,6 +282,7 @@ export default class StoryPreviewV extends Vue {

// reload preview page with FR config
changeLang(): void {
this.broadcast?.close();
const newLang = this.lang === 'en' ? 'fr' : 'en';
const routeData = this.$router.resolve({
name: 'preview',
Expand Down
2 changes: 2 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createApp } from 'vue';
import App from './app.vue';
import { createPinia } from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';

import './router/componentHooks';
import router from './router';
Expand Down Expand Up @@ -40,6 +41,7 @@ import { Truncate } from '@/directives/truncate/truncate';

const app = createApp(App);
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);

app.use(pinia)
.use(router)
Expand Down
8 changes: 8 additions & 0 deletions src/stores/lockStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ export const useLockStore = defineStore('lock', {
confirmationTimeout: undefined as NodeJS.Timeout | undefined, // the timer to show the session extension confirmation modal
endTimeout: undefined as NodeJS.Timeout | undefined // the timer to kill the session due to timeout
}),
persist: true,
actions: {
// Opens a connection with the web socket
initConnection() {
console.log('lockStore - initConnection');
const socketUrl = `${
import.meta.env.VITE_APP_CURR_ENV ? import.meta.env.VITE_APP_API_URL : 'http://localhost:6040'
}`;
Expand All @@ -38,6 +40,9 @@ export const useLockStore = defineStore('lock', {
// Attempts to lock a storyline for this user.
// Returns a promise that resolves if the lock was successfully fetched and rejects if it was not.
lockStoryline(uuid: string): Promise<void> {
console.log('lockStore - lockStoryline');
console.log(this);
console.log(this.$state);
// Stop the previous storyline's timer.
clearInterval(this.timeInterval);
return new Promise((resolve, reject) => {
Expand All @@ -59,6 +64,8 @@ export const useLockStore = defineStore('lock', {
this.uuid = uuid;
this.secret = this.result.secret;
this.broadcast = new BroadcastChannel(this.result.secret);
console.log('lockStore - name of BC');
console.log(this.result.secret);
resolve();
}
}
Expand All @@ -79,6 +86,7 @@ export const useLockStore = defineStore('lock', {
},
// Resets the current session back to a full 30 minutes.
resetSession(overrideTime?: number) {
console.log('lockStore - resetSession');
this.timeRemaining =
overrideTime !== undefined
? overrideTime
Expand Down
Loading