Remove vue tour
This commit is contained in:
@@ -37,7 +37,6 @@
|
||||
"vue-plugin-load-script": "^1.2.0",
|
||||
"vue-router": "3.1.6",
|
||||
"vue-select": "^3.18.3",
|
||||
"vue-tour": "^2.0.0",
|
||||
"vuedraggable": "^2.23.2",
|
||||
"vuex": "3.1.3"
|
||||
},
|
||||
|
||||
@@ -99,34 +99,12 @@
|
||||
</div>
|
||||
</b-container>
|
||||
</div>
|
||||
|
||||
<portal
|
||||
to="topbar-help-dropdown"
|
||||
>
|
||||
<b-dropdown-item
|
||||
data-test-id="dropdown-helper-tour"
|
||||
@click="$refs.tour.onStartClick()"
|
||||
>
|
||||
{{ $t('start-tour') }}
|
||||
</b-dropdown-item>
|
||||
</portal>
|
||||
|
||||
<tour-start
|
||||
@start="startTour"
|
||||
/>
|
||||
|
||||
<tour
|
||||
ref="tour"
|
||||
name="app-list"
|
||||
:steps="filteredSteps"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex'
|
||||
import Draggable from 'vuedraggable'
|
||||
import { components, url } from '@cortezaproject/corteza-vue'
|
||||
const { Tour, TourStart, CInputSearch } = components
|
||||
import { url } from '@cortezaproject/corteza-vue'
|
||||
|
||||
export default {
|
||||
i18nOptions: {
|
||||
@@ -135,9 +113,6 @@ export default {
|
||||
|
||||
components: {
|
||||
Draggable,
|
||||
Tour,
|
||||
TourStart,
|
||||
CInputSearch,
|
||||
},
|
||||
|
||||
props: {
|
||||
@@ -253,10 +228,6 @@ export default {
|
||||
await this.reorderApp(applicationIDs)
|
||||
},
|
||||
|
||||
startTour () {
|
||||
this.$refs.tour.onStart()
|
||||
},
|
||||
|
||||
logoUrl (app) {
|
||||
if (!app.unify.logo) {
|
||||
return 'applications/default-app.png'
|
||||
|
||||
@@ -2,7 +2,6 @@ import Vue from 'vue'
|
||||
import BootstrapVue from 'bootstrap-vue'
|
||||
import Router from 'vue-router'
|
||||
import Vuex from 'vuex'
|
||||
import VueTour from 'vue-tour'
|
||||
import VueNativeSock from 'vue-native-websocket'
|
||||
|
||||
import { plugins, websocket } from '@cortezaproject/corteza-vue'
|
||||
@@ -20,7 +19,6 @@ Vue.use(plugins.Auth(), {
|
||||
rootApp: true,
|
||||
})
|
||||
|
||||
Vue.use(VueTour)
|
||||
Vue.use(Router)
|
||||
Vue.use(Vuex)
|
||||
Vue.use(BootstrapVue)
|
||||
|
||||
@@ -873,11 +873,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.5.tgz#db5a11bf66bdab39569719555b0f76e138d7bd64"
|
||||
integrity sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==
|
||||
|
||||
"@popperjs/core@^2.9.1":
|
||||
version "2.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.10.1.tgz#728ecd95ab207aab8a9a4e421f0422db329232be"
|
||||
integrity sha512-HnUhk1Sy9IuKrxEMdIRCxpIqPw6BFsbYSEUO9p/hNw5sMld/+3OLMWQP80F8/db9qsv3qUjs7ZR5bS/R+iinXw==
|
||||
|
||||
"@sinonjs/commons@^1", "@sinonjs/commons@^1.3.0", "@sinonjs/commons@^1.4.0", "@sinonjs/commons@^1.7.0":
|
||||
version "1.8.3"
|
||||
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d"
|
||||
@@ -5036,11 +5031,6 @@ hash-sum@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-1.0.2.tgz#33b40777754c6432573c120cc3808bbd10d47f04"
|
||||
integrity sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=
|
||||
|
||||
hash-sum@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-2.0.0.tgz#81d01bb5de8ea4a214ad5d6ead1b523460b0b45a"
|
||||
integrity sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==
|
||||
|
||||
hash.js@^1.0.0, hash.js@^1.0.3:
|
||||
version "1.1.7"
|
||||
resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
|
||||
@@ -6061,11 +6051,6 @@ jsprim@^1.2.2:
|
||||
json-schema "0.2.3"
|
||||
verror "1.10.0"
|
||||
|
||||
jump.js@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/jump.js/-/jump.js-1.0.2.tgz#e0641b47f40a38f2139c25fda0500bf28e43015a"
|
||||
integrity sha1-4GQbR/QKOPITnCX9oFAL8o5DAVo=
|
||||
|
||||
just-extend@^4.0.2:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.2.1.tgz#ef5e589afb61e5d66b24eca749409a8939a8c744"
|
||||
@@ -10357,16 +10342,6 @@ vue-template-es2015-compiler@^1.9.0:
|
||||
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
|
||||
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
|
||||
|
||||
vue-tour@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/vue-tour/-/vue-tour-2.0.0.tgz#aa4489cfc9f9090ca57d3208a074010f3be8ec05"
|
||||
integrity sha512-vhKzqdhunQ3EoO1733UxhOB389u3EKv2X8JqYhX4tIq4ilqlZtnY3azPFBYPFmnAqHn5RyZBrP2CpqSaxTs8og==
|
||||
dependencies:
|
||||
"@popperjs/core" "^2.9.1"
|
||||
hash-sum "^2.0.0"
|
||||
jump.js "^1.0.2"
|
||||
vue "^2.6.12"
|
||||
|
||||
vue2-ace-editor@^0.0.15:
|
||||
version "0.0.15"
|
||||
resolved "https://registry.yarnpkg.com/vue2-ace-editor/-/vue2-ace-editor-0.0.15.tgz#569b208e54ae771ae1edd3b8902ac42f0edc74e3"
|
||||
@@ -10379,7 +10354,7 @@ vue2-leaflet@^2.7.1:
|
||||
resolved "https://registry.yarnpkg.com/vue2-leaflet/-/vue2-leaflet-2.7.1.tgz#2f95c287621bf778f10804c88223877f5c049257"
|
||||
integrity sha512-K7HOlzRhjt3Z7+IvTqEavIBRbmCwSZSCVUlz9u4Rc+3xGCLsHKz4TAL4diAmfHElCQdPPVdZdJk8wPUt2fu6WQ==
|
||||
|
||||
vue@2.6.14, vue@^2.6.12:
|
||||
vue@2.6.14:
|
||||
version "2.6.14"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.14.tgz#e51aa5250250d569a3fbad3a8a5a687d6036e235"
|
||||
integrity sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==
|
||||
|
||||
@@ -114,8 +114,7 @@
|
||||
"typescript": "^3.7.4",
|
||||
"vue-eslint-parser": "^9.3.2",
|
||||
"vue-property-decorator": "^8.3.0",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"vue-tour": "^2.0.0"
|
||||
"vue-template-compiler": "^2.6.14"
|
||||
},
|
||||
"resolutions": {
|
||||
"**/**/yargs-parser": "^13.1.2",
|
||||
|
||||
@@ -1,212 +0,0 @@
|
||||
<template>
|
||||
<v-tour
|
||||
v-if="tour !== null"
|
||||
:name="tour.name"
|
||||
:steps="tour.steps"
|
||||
:options="tour"
|
||||
:callbacks="this.callbacks"
|
||||
@onStop="onStop"
|
||||
>
|
||||
<template slot-scope="tour">
|
||||
<transition name="fade">
|
||||
<template v-for="(step, index) of tour.steps">
|
||||
<v-step
|
||||
v-if="tour.currentStep === index"
|
||||
:key="index"
|
||||
class="shadow p-3 text-light text-center"
|
||||
:step="step"
|
||||
:previous-step="tour.previousStep"
|
||||
:next-step="tour.nextStep"
|
||||
:stop="tour.stop"
|
||||
:is-first="tour.isFirst"
|
||||
:is-last="tour.isLast"
|
||||
:labels="tour.labels"
|
||||
@onStop="onStop"
|
||||
>
|
||||
<div slot="header">
|
||||
<h5
|
||||
v-if="(step.header || {}).title"
|
||||
v-html="$t(step.header.title)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div slot="content">
|
||||
<div class="p-1 mb-2">
|
||||
<div v-html="$t(step.content)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
slot="actions"
|
||||
class="d-flex justify-content-between align-items-center"
|
||||
>
|
||||
<b-button
|
||||
data-test-id="button-stop-tour"
|
||||
variant="outline-light"
|
||||
class="border-0"
|
||||
@click="onStop"
|
||||
>
|
||||
<template v-if="tour.isLast && !(callbacks || {}).onNextRedirect">
|
||||
{{ $t('buttons.end') }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ $t('buttons.skip') }}
|
||||
</template>
|
||||
</b-button>
|
||||
|
||||
<div>
|
||||
<b-button
|
||||
data-test-id="button-previous"
|
||||
v-if="tour.isFirst && (callbacks || {}).onPrevRedirect"
|
||||
variant="outline-light"
|
||||
class="border-0"
|
||||
:href="callbacks.onPrevRedirect"
|
||||
>
|
||||
{{ $t('buttons.previous') }}
|
||||
</b-button>
|
||||
<b-button
|
||||
data-test-id="button-previous"
|
||||
v-else-if="!tour.isFirst"
|
||||
variant="outline-light"
|
||||
class="border-0"
|
||||
@click="tour.previousStep"
|
||||
>
|
||||
{{ $t('buttons.previous') }}
|
||||
</b-button>
|
||||
<b-button
|
||||
data-test-id="button-next"
|
||||
v-if="tour.isLast && (callbacks || {}).onNextRedirect"
|
||||
variant="outline-light"
|
||||
class="border-0"
|
||||
:href="callbacks.onNextRedirect"
|
||||
>
|
||||
{{ $t('buttons.next') }}
|
||||
</b-button>
|
||||
<b-button
|
||||
data-test-id="button-next"
|
||||
v-else-if="!tour.isLast"
|
||||
variant="light"
|
||||
@click="tour.nextStep"
|
||||
>
|
||||
{{ $t('buttons.next') }}
|
||||
</b-button>
|
||||
</div>
|
||||
</div>
|
||||
</v-step>
|
||||
</template>
|
||||
</transition>
|
||||
</template>
|
||||
</v-tour>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'TourComponent',
|
||||
i18nOptions: {
|
||||
namespaces: 'onboarding-tour',
|
||||
},
|
||||
|
||||
props: {
|
||||
name: String,
|
||||
|
||||
callbacks: {
|
||||
type: Object,
|
||||
},
|
||||
|
||||
steps: {
|
||||
default: () => [],
|
||||
type: Array,
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
labels () {
|
||||
return this.tour.labels
|
||||
},
|
||||
|
||||
tour () {
|
||||
return {
|
||||
name: this.name,
|
||||
steps: this.steps.map(step => {
|
||||
return {
|
||||
name: step,
|
||||
target: `[data-v-onboarding="${step}"]`,
|
||||
header: {
|
||||
title: this.$t(`steps.${step}.title`),
|
||||
},
|
||||
content: this.$t(`steps.${step}.content`),
|
||||
}
|
||||
}),
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
onStart () {
|
||||
if (JSON.parse(localStorage.getItem('corteza.tour')) && this.tour.steps.length) {
|
||||
this.$tours[this.tour.name].start()
|
||||
}
|
||||
},
|
||||
|
||||
onStop () {
|
||||
localStorage.setItem('corteza.tour', JSON.stringify(false))
|
||||
this.$tours[this.tour.name].stop()
|
||||
},
|
||||
|
||||
onStartClick () {
|
||||
localStorage.setItem('corteza.tour', JSON.stringify(true))
|
||||
this.onStart()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.v-step {
|
||||
background: var(--primary);
|
||||
max-width: 320px;
|
||||
z-index: 10000;
|
||||
border-radius: 1.1rem;
|
||||
}
|
||||
.v-step--sticky {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
-webkit-transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
.v-step--sticky .v-step__arrow {
|
||||
display: none;
|
||||
}
|
||||
.v-step__arrow,
|
||||
.v-step__arrow:before {
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: inherit;
|
||||
}
|
||||
.v-step__arrow {
|
||||
visibility: hidden;
|
||||
}
|
||||
.v-step__arrow--dark:before {
|
||||
background: var(--primary);
|
||||
}
|
||||
.v-step__arrow:before {
|
||||
visibility: visible;
|
||||
content: "";
|
||||
-webkit-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
margin-left: -5px;
|
||||
}
|
||||
.v-step[data-popper-placement^="top"] > .v-step__arrow {
|
||||
bottom: -5px;
|
||||
}
|
||||
.v-step[data-popper-placement^="bottom"] > .v-step__arrow {
|
||||
top: -5px;
|
||||
}
|
||||
.v-step[data-popper-placement^="right"] > .v-step__arrow {
|
||||
left: -5px;
|
||||
}
|
||||
.v-step[data-popper-placement^="left"] > .v-step__arrow {
|
||||
right: -5px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,52 +0,0 @@
|
||||
<template>
|
||||
<b-modal
|
||||
id="tourStart"
|
||||
size="lg"
|
||||
:title="$t('start.welcome')"
|
||||
:ok-title="$t('start.show')"
|
||||
:cancel-title="$t('start.skip')"
|
||||
body-class="p-0"
|
||||
no-fade
|
||||
@ok="onSave"
|
||||
@cancel="onCancel"
|
||||
>
|
||||
<div
|
||||
class="card-body"
|
||||
>
|
||||
{{ $t('start.instructions') }}
|
||||
</div>
|
||||
</b-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
i18nOptions: {
|
||||
namespaces: 'onboarding-tour',
|
||||
},
|
||||
|
||||
created () {
|
||||
this.$nextTick(() => {
|
||||
if (window.localStorage.getItem('corteza.tour') === null) {
|
||||
this.$bvModal.show('tourStart')
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
onSave () {
|
||||
this.updateStorage(true)
|
||||
this.$emit('start')
|
||||
this.showModal = false
|
||||
},
|
||||
|
||||
onCancel () {
|
||||
this.updateStorage(false)
|
||||
this.showModal = false
|
||||
},
|
||||
|
||||
updateStorage (status) {
|
||||
window.localStorage.setItem('corteza.tour', JSON.stringify(status))
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,2 +0,0 @@
|
||||
export { default as Tour } from './Tour.vue'
|
||||
export { default as TourStart } from './TourStart.vue'
|
||||
@@ -44,11 +44,6 @@ export {
|
||||
CSidebarNavItems,
|
||||
} from './navigation'
|
||||
|
||||
export {
|
||||
Tour,
|
||||
TourStart,
|
||||
} from './Tour'
|
||||
|
||||
export {
|
||||
CToaster,
|
||||
CToasterLink,
|
||||
|
||||
+1
-21
@@ -1273,7 +1273,7 @@
|
||||
dependencies:
|
||||
deepmerge "^2.0.0"
|
||||
|
||||
"@popperjs/core@^2.11.2", "@popperjs/core@^2.9.1":
|
||||
"@popperjs/core@^2.11.2":
|
||||
version "2.11.2"
|
||||
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.2.tgz#830beaec4b4091a9e9398ac50f865ddea52186b9"
|
||||
integrity sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==
|
||||
@@ -6951,11 +6951,6 @@ jstransformer@1.0.0:
|
||||
is-promise "^2.0.0"
|
||||
promise "^7.0.1"
|
||||
|
||||
jump.js@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/jump.js/-/jump.js-1.0.2.tgz#e0641b47f40a38f2139c25fda0500bf28e43015a"
|
||||
integrity sha1-4GQbR/QKOPITnCX9oFAL8o5DAVo=
|
||||
|
||||
just-extend@^4.0.2:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.2.1.tgz#ef5e589afb61e5d66b24eca749409a8939a8c744"
|
||||
@@ -11793,16 +11788,6 @@ vue-template-es2015-compiler@^1.9.0:
|
||||
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
|
||||
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
|
||||
|
||||
vue-tour@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/vue-tour/-/vue-tour-2.0.0.tgz#aa4489cfc9f9090ca57d3208a074010f3be8ec05"
|
||||
integrity sha512-vhKzqdhunQ3EoO1733UxhOB389u3EKv2X8JqYhX4tIq4ilqlZtnY3azPFBYPFmnAqHn5RyZBrP2CpqSaxTs8og==
|
||||
dependencies:
|
||||
"@popperjs/core" "^2.9.1"
|
||||
hash-sum "^2.0.0"
|
||||
jump.js "^1.0.2"
|
||||
vue "^2.6.12"
|
||||
|
||||
vue2-ace-editor@^0.0.15:
|
||||
version "0.0.15"
|
||||
resolved "https://registry.yarnpkg.com/vue2-ace-editor/-/vue2-ace-editor-0.0.15.tgz#569b208e54ae771ae1edd3b8902ac42f0edc74e3"
|
||||
@@ -11815,11 +11800,6 @@ vue2-leaflet@^2.7.1:
|
||||
resolved "https://registry.yarnpkg.com/vue2-leaflet/-/vue2-leaflet-2.7.1.tgz#2f95c287621bf778f10804c88223877f5c049257"
|
||||
integrity sha512-K7HOlzRhjt3Z7+IvTqEavIBRbmCwSZSCVUlz9u4Rc+3xGCLsHKz4TAL4diAmfHElCQdPPVdZdJk8wPUt2fu6WQ==
|
||||
|
||||
vue@^2.6.12:
|
||||
version "2.6.14"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.14.tgz#e51aa5250250d569a3fbad3a8a5a687d6036e235"
|
||||
integrity sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==
|
||||
|
||||
vuedraggable@^2.23.0:
|
||||
version "2.24.3"
|
||||
resolved "https://registry.yarnpkg.com/vuedraggable/-/vuedraggable-2.24.3.tgz#43c93849b746a24ce503e123d5b259c701ba0d19"
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
no-applications: No applications with this name
|
||||
search: Type here to search
|
||||
start-tour: Start tour
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
start:
|
||||
welcome: Welcome to Corteza
|
||||
instructions: Hello! You have successfully created your Corteza account. Are you ready to get started? Click on the "Show me" button below for a quick guide through the basic functionalities.
|
||||
skip: Skip tour
|
||||
show: Show me
|
||||
|
||||
buttons:
|
||||
skip: Skip tour
|
||||
previous: Back
|
||||
next: Next
|
||||
end: End
|
||||
|
||||
steps:
|
||||
app-list:
|
||||
title: Application Menu
|
||||
content: This is where you can see the list of available applications. When in an application, you can always return to this list by clicking on the 6-dots icon in the top right corner.
|
||||
crm:
|
||||
title: Example Namespace - CRM
|
||||
content: Here you can access CRM, an example of the low-code configuration. You can navigate through the application from the sidebar on the left where you'll see a list of available pages. To insert an example data, click on a "+ Add" button on any record list.
|
||||
low-code:
|
||||
title: List of Low-Code applications (namespaces)
|
||||
content: Here you can create a new Low-Code application (namespace) or start working on some pre-configured applications (e.g. CRM). These applications do not show up on the Application Menu by default.
|
||||
reporter:
|
||||
title: List of Reports
|
||||
content: To make advanced dashboard views with aggregated data from several modules, different tables and charts, start building a new report.
|
||||
profile:
|
||||
title: Profile Settings
|
||||
content: To update your profile settings, set the language, change the password or set up 2-factor authentication, follow the link below the user icon.
|
||||
workflow:
|
||||
title: List of Workflows
|
||||
content: Take your Low-Code applications to the next level with the visual workflow builder, where you can automate any process to cover your organization's needs. Start building a new workflow or review the existing ones.
|
||||
Reference in New Issue
Block a user