debian-mirror-gitlab/app/assets/javascripts/ide/components/preview/clientside.vue

192 lines
5.1 KiB
Vue
Raw Normal View History

2018-11-18 11:00:15 +05:30
<script>
2021-03-11 19:13:27 +05:30
import { GlLoadingIcon } from '@gitlab/ui';
import { listen } from 'codesandbox-api';
2021-03-08 18:12:59 +05:30
import { isEmpty, debounce } from 'lodash';
2018-11-18 11:00:15 +05:30
import { Manager } from 'smooshpack';
2021-03-11 19:13:27 +05:30
import { mapActions, mapGetters, mapState } from 'vuex';
2022-04-04 11:22:00 +05:30
import {
packageJsonPath,
LIVE_PREVIEW_DEBOUNCE,
PING_USAGE_PREVIEW_KEY,
PING_USAGE_PREVIEW_SUCCESS_KEY,
} from '../../constants';
2021-03-08 18:12:59 +05:30
import eventHub from '../../eventhub';
2021-03-11 19:13:27 +05:30
import { createPathWithExt } from '../../utils';
import Navigator from './navigator.vue';
2018-11-18 11:00:15 +05:30
export default {
components: {
Navigator,
2018-12-13 13:39:08 +05:30
GlLoadingIcon,
2018-11-18 11:00:15 +05:30
},
data() {
return {
manager: {},
loading: false,
sandpackReady: false,
};
},
computed: {
2020-04-08 14:13:33 +05:30
...mapState(['entries', 'promotionSvgPath', 'links', 'codesandboxBundlerUrl']),
2018-11-18 11:00:15 +05:30
...mapGetters(['packageJson', 'currentProject']),
normalizedEntries() {
return Object.keys(this.entries).reduce((acc, path) => {
const file = this.entries[path];
if (file.type === 'tree' || !(file.raw || file.content)) return acc;
return {
...acc,
[`/${path}`]: {
code: file.content || file.raw,
},
};
}, {});
},
mainEntry() {
if (!this.packageJson.raw) return false;
const parsedPackage = JSON.parse(this.packageJson.raw);
return parsedPackage.main;
},
showPreview() {
return this.mainEntry && !this.loading;
},
showEmptyState() {
return !this.mainEntry && !this.loading;
},
showOpenInCodeSandbox() {
return this.currentProject && this.currentProject.visibility === 'public';
},
sandboxOpts() {
return {
files: { ...this.normalizedEntries },
entry: `/${this.mainEntry}`,
showOpenInCodeSandbox: this.showOpenInCodeSandbox,
};
},
},
2022-04-04 11:22:00 +05:30
watch: {
sandpackReady: {
handler(val) {
if (val) {
this.pingUsage(PING_USAGE_PREVIEW_SUCCESS_KEY);
}
},
},
},
2018-11-18 11:00:15 +05:30
mounted() {
2021-03-08 18:12:59 +05:30
this.onFilesChangeCallback = debounce(() => this.update(), LIVE_PREVIEW_DEBOUNCE);
eventHub.$on('ide.files.change', this.onFilesChangeCallback);
2018-11-18 11:00:15 +05:30
this.loading = true;
return this.loadFileContent(packageJsonPath)
.then(() => {
this.loading = false;
})
.then(() => this.$nextTick())
.then(() => this.initPreview());
},
beforeDestroy() {
2021-03-08 18:12:59 +05:30
// Setting sandpackReady = false protects us form a phantom `update()` being called when `debounce` finishes.
this.sandpackReady = false;
eventHub.$off('ide.files.change', this.onFilesChangeCallback);
2020-04-22 19:07:51 +05:30
if (!isEmpty(this.manager)) {
2018-11-18 11:00:15 +05:30
this.manager.listener();
}
2021-03-08 18:12:59 +05:30
2018-11-18 11:00:15 +05:30
this.manager = {};
if (this.listener) {
this.listener();
}
},
methods: {
...mapActions(['getFileData', 'getRawFileData']),
2019-12-26 22:10:19 +05:30
...mapActions('clientside', ['pingUsage']),
2018-11-18 11:00:15 +05:30
loadFileContent(path) {
return this.getFileData({ path, makeFileActive: false }).then(() =>
this.getRawFileData({ path }),
);
},
initPreview() {
if (!this.mainEntry) return null;
2022-04-04 11:22:00 +05:30
this.pingUsage(PING_USAGE_PREVIEW_KEY);
2019-12-26 22:10:19 +05:30
2018-11-18 11:00:15 +05:30
return this.loadFileContent(this.mainEntry)
.then(() => this.$nextTick())
.then(() => {
2020-04-08 14:13:33 +05:30
this.initManager();
2018-11-18 11:00:15 +05:30
2021-03-08 18:12:59 +05:30
this.listener = listen((e) => {
2018-11-18 11:00:15 +05:30
switch (e.type) {
case 'done':
this.sandpackReady = true;
break;
default:
break;
}
});
});
},
update() {
if (!this.sandpackReady) return;
2021-03-08 18:12:59 +05:30
if (isEmpty(this.manager)) {
this.initPreview();
2018-11-18 11:00:15 +05:30
2021-03-08 18:12:59 +05:30
return;
}
2018-11-18 11:00:15 +05:30
2021-03-08 18:12:59 +05:30
this.manager.updatePreview(this.sandboxOpts);
2018-11-18 11:00:15 +05:30
},
2020-04-08 14:13:33 +05:30
initManager() {
const { codesandboxBundlerUrl: bundlerURL } = this;
const settings = {
fileResolver: {
2021-03-08 18:12:59 +05:30
isFile: (p) => Promise.resolve(Boolean(this.entries[createPathWithExt(p)])),
readFile: (p) => this.loadFileContent(createPathWithExt(p)).then((content) => content),
2020-04-08 14:13:33 +05:30
},
...(bundlerURL ? { bundlerURL } : {}),
};
this.manager = new Manager('#ide-preview', this.sandboxOpts, settings);
2018-11-18 11:00:15 +05:30
},
},
};
</script>
<template>
2021-02-22 17:27:13 +05:30
<div class="preview h-100 w-100 d-flex flex-column gl-bg-white">
2018-11-18 11:00:15 +05:30
<template v-if="showPreview">
2019-02-15 15:39:39 +05:30
<navigator :manager="manager" />
2018-11-18 11:00:15 +05:30
<div id="ide-preview"></div>
</template>
<div
v-else-if="showEmptyState"
v-once
class="d-flex h-100 flex-column align-items-center justify-content-center svg-content"
>
2019-02-15 15:39:39 +05:30
<img :src="promotionSvgPath" :alt="s__('IDE|Live Preview')" width="130" height="100" />
<h3>{{ s__('IDE|Live Preview') }}</h3>
2018-11-18 11:00:15 +05:30
<p class="text-center">
{{ s__('IDE|Preview your web application using Web IDE client-side evaluation.') }}
</p>
<a
:href="links.webIDEHelpPagePath"
2021-03-11 19:13:27 +05:30
class="btn gl-button btn-confirm"
2018-11-18 11:00:15 +05:30
target="_blank"
rel="noopener noreferrer"
>
{{ s__('IDE|Get started with Live Preview') }}
</a>
</div>
2020-04-22 19:07:51 +05:30
<gl-loading-icon v-else size="lg" class="align-self-center mt-auto mb-auto" />
2018-11-18 11:00:15 +05:30
</div>
</template>