fix: show error page if there is no access

This commit is contained in:
Shariq Ansari 2025-04-08 15:28:54 +05:30
parent e92ee3b730
commit fa56dc4791
5 changed files with 78 additions and 11 deletions

View File

@ -94,6 +94,7 @@ declare module 'vue' {
EmailTemplatesListView: typeof import('./src/components/ListViews/EmailTemplatesListView.vue')['default'] EmailTemplatesListView: typeof import('./src/components/ListViews/EmailTemplatesListView.vue')['default']
ERPNextIcon: typeof import('./src/components/Icons/ERPNextIcon.vue')['default'] ERPNextIcon: typeof import('./src/components/Icons/ERPNextIcon.vue')['default']
ERPNextSettings: typeof import('./src/components/Settings/ERPNextSettings.vue')['default'] ERPNextSettings: typeof import('./src/components/Settings/ERPNextSettings.vue')['default']
ErrorPage: typeof import('./src/components/ErrorPage.vue')['default']
ExotelCallUI: typeof import('./src/components/Telephony/ExotelCallUI.vue')['default'] ExotelCallUI: typeof import('./src/components/Telephony/ExotelCallUI.vue')['default']
ExportIcon: typeof import('./src/components/Icons/ExportIcon.vue')['default'] ExportIcon: typeof import('./src/components/Icons/ExportIcon.vue')['default']
ExternalLinkIcon: typeof import('./src/components/Icons/ExternalLinkIcon.vue')['default'] ExternalLinkIcon: typeof import('./src/components/Icons/ExternalLinkIcon.vue')['default']

View File

@ -8,7 +8,7 @@
</Breadcrumbs> </Breadcrumbs>
</template> </template>
</LayoutHeader> </LayoutHeader>
<div ref="parentRef" class="flex h-full"> <div v-if="contact.data" ref="parentRef" class="flex h-full">
<Resizer <Resizer
v-if="contact.data" v-if="contact.data"
:parent="$refs.parentRef" :parent="$refs.parentRef"
@ -168,10 +168,12 @@
</template> </template>
</Tabs> </Tabs>
</div> </div>
<ErrorPage v-else :errorTitle="errorTitle" :errorMessage="errorMessage" />
<AddressModal v-model="showAddressModal" v-model:address="_address" /> <AddressModal v-model="showAddressModal" v-model:address="_address" />
</template> </template>
<script setup> <script setup>
import ErrorPage from '@/components/ErrorPage.vue'
import Resizer from '@/components/Resizer.vue' import Resizer from '@/components/Resizer.vue'
import Icon from '@/components/Icon.vue' import Icon from '@/components/Icon.vue'
import SidePanelLayout from '@/components/SidePanelLayout.vue' import SidePanelLayout from '@/components/SidePanelLayout.vue'
@ -202,6 +204,7 @@ import {
} from 'frappe-ui' } from 'frappe-ui'
import { ref, computed, h } from 'vue' import { ref, computed, h } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { errorMessage as _errorMessage } from '../utils'
const { brand } = getSettings() const { brand } = getSettings()
const { $dialog, makeCall } = globalStore() const { $dialog, makeCall } = globalStore()
@ -225,6 +228,9 @@ const showAddressModal = ref(false)
const _contact = ref({}) const _contact = ref({})
const _address = ref({}) const _address = ref({})
const errorTitle = ref('')
const errorMessage = ref('')
const contact = createResource({ const contact = createResource({
url: 'crm.api.contact.get_contact', url: 'crm.api.contact.get_contact',
cache: ['contact', props.contactId], cache: ['contact', props.contactId],
@ -237,6 +243,18 @@ const contact = createResource({
mobile_no: data.mobile_no, mobile_no: data.mobile_no,
} }
}, },
onSuccess: () => {
errorTitle.value = ''
errorMessage.value = ''
},
onError: (err) => {
if (err.messages?.[0]) {
errorTitle.value = __('Not permitted')
errorMessage.value = __(err.messages?.[0])
} else {
router.push({ name: 'Contacts' })
}
},
}) })
const breadcrumbs = computed(() => { const breadcrumbs = computed(() => {

View File

@ -89,7 +89,7 @@
@click=" @click="
deal.data.email deal.data.email
? openEmailBox() ? openEmailBox()
: errorMessage(__('No email set')) : _errorMessage(__('No email set'))
" "
/> />
</Button> </Button>
@ -103,7 +103,7 @@
@click=" @click="
deal.data.website deal.data.website
? openWebsite(deal.data.website) ? openWebsite(deal.data.website)
: errorMessage(__('No website set')) : _errorMessage(__('No website set'))
" "
/> />
</Button> </Button>
@ -267,6 +267,7 @@
</div> </div>
</Resizer> </Resizer>
</div> </div>
<ErrorPage v-else :errorTitle="errorTitle" :errorMessage="errorMessage" />
<OrganizationModal <OrganizationModal
v-model="showOrganizationModal" v-model="showOrganizationModal"
v-model:organization="_organization" v-model:organization="_organization"
@ -297,6 +298,7 @@
/> />
</template> </template>
<script setup> <script setup>
import ErrorPage from '@/components/ErrorPage.vue'
import Icon from '@/components/Icon.vue' import Icon from '@/components/Icon.vue'
import Resizer from '@/components/Resizer.vue' import Resizer from '@/components/Resizer.vue'
import LoadingIndicator from '@/components/Icons/LoadingIndicator.vue' import LoadingIndicator from '@/components/Icons/LoadingIndicator.vue'
@ -330,7 +332,7 @@ import {
createToast, createToast,
setupAssignees, setupAssignees,
setupCustomizations, setupCustomizations,
errorMessage, errorMessage as _errorMessage,
copyToClipboard, copyToClipboard,
} from '@/utils' } from '@/utils'
import { getView } from '@/utils/view' import { getView } from '@/utils/view'
@ -372,11 +374,17 @@ const props = defineProps({
}, },
}) })
const errorTitle = ref('')
const errorMessage = ref('')
const deal = createResource({ const deal = createResource({
url: 'crm.fcrm.doctype.crm_deal.api.get_deal', url: 'crm.fcrm.doctype.crm_deal.api.get_deal',
params: { name: props.dealId }, params: { name: props.dealId },
cache: ['deal', props.dealId], cache: ['deal', props.dealId],
onSuccess: (data) => { onSuccess: (data) => {
errorTitle.value = ''
errorMessage.value = ''
if (data.organization) { if (data.organization) {
organization.update({ organization.update({
params: { doctype: 'CRM Organization', name: data.organization }, params: { doctype: 'CRM Organization', name: data.organization },
@ -401,6 +409,14 @@ const deal = createResource({
call, call,
}) })
}, },
onError: (err) => {
if (err.messages?.[0]) {
errorTitle.value = __('Not permitted')
errorMessage.value = __(err.messages?.[0])
} else {
router.push({ name: 'Deals' })
}
},
}) })
const organization = createResource({ const organization = createResource({
@ -698,12 +714,12 @@ function triggerCall() {
let mobile_no = primaryContact.mobile_no || null let mobile_no = primaryContact.mobile_no || null
if (!primaryContact) { if (!primaryContact) {
errorMessage(__('No primary contact set')) _errorMessage(__('No primary contact set'))
return return
} }
if (!mobile_no) { if (!mobile_no) {
errorMessage(__('No mobile number set')) _errorMessage(__('No mobile number set'))
return return
} }

View File

@ -124,7 +124,7 @@
() => () =>
lead.data.mobile_no lead.data.mobile_no
? makeCall(lead.data.mobile_no) ? makeCall(lead.data.mobile_no)
: errorMessage(__('No phone number set')) : _errorMessage(__('No phone number set'))
" "
> >
<PhoneIcon class="h-4 w-4" /> <PhoneIcon class="h-4 w-4" />
@ -139,7 +139,7 @@
@click=" @click="
lead.data.email lead.data.email
? openEmailBox() ? openEmailBox()
: errorMessage(__('No email set')) : _errorMessage(__('No email set'))
" "
/> />
</Button> </Button>
@ -153,7 +153,7 @@
@click=" @click="
lead.data.website lead.data.website
? openWebsite(lead.data.website) ? openWebsite(lead.data.website)
: errorMessage(__('No website set')) : _errorMessage(__('No website set'))
" "
/> />
</Button> </Button>
@ -191,6 +191,7 @@
</div> </div>
</Resizer> </Resizer>
</div> </div>
<ErrorPage v-else :errorTitle="errorTitle" :errorMessage="errorMessage" />
<Dialog <Dialog
v-model="showConvertToDealModal" v-model="showConvertToDealModal"
:options="{ :options="{
@ -309,6 +310,7 @@
/> />
</template> </template>
<script setup> <script setup>
import ErrorPage from '@/components/ErrorPage.vue'
import Icon from '@/components/Icon.vue' import Icon from '@/components/Icon.vue'
import Resizer from '@/components/Resizer.vue' import Resizer from '@/components/Resizer.vue'
import ActivityIcon from '@/components/Icons/ActivityIcon.vue' import ActivityIcon from '@/components/Icons/ActivityIcon.vue'
@ -342,7 +344,7 @@ import {
createToast, createToast,
setupAssignees, setupAssignees,
setupCustomizations, setupCustomizations,
errorMessage, errorMessage as _errorMessage,
copyToClipboard, copyToClipboard,
} from '@/utils' } from '@/utils'
import { getView } from '@/utils/view' import { getView } from '@/utils/view'
@ -392,11 +394,16 @@ const props = defineProps({
}, },
}) })
const errorTitle = ref('')
const errorMessage = ref('')
const lead = createResource({ const lead = createResource({
url: 'crm.fcrm.doctype.crm_lead.api.get_lead', url: 'crm.fcrm.doctype.crm_lead.api.get_lead',
params: { name: props.leadId }, params: { name: props.leadId },
cache: ['lead', props.leadId], cache: ['lead', props.leadId],
onSuccess: (data) => { onSuccess: (data) => {
errorTitle.value = ''
errorMessage.value = ''
setupAssignees(lead) setupAssignees(lead)
setupCustomizations(lead, { setupCustomizations(lead, {
doc: data, doc: data,
@ -410,6 +417,14 @@ const lead = createResource({
call, call,
}) })
}, },
onError: (err) => {
if (err.messages?.[0]) {
errorTitle.value = __('Not permitted')
errorMessage.value = __(err.messages?.[0])
} else {
router.push({ name: 'Leads' })
}
},
}) })
onMounted(() => { onMounted(() => {

View File

@ -8,7 +8,7 @@
</Breadcrumbs> </Breadcrumbs>
</template> </template>
</LayoutHeader> </LayoutHeader>
<div ref="parentRef" class="flex h-full"> <div v-if="organization.doc" ref="parentRef" class="flex h-full">
<Resizer <Resizer
v-if="organization.doc" v-if="organization.doc"
:parent="$refs.parentRef" :parent="$refs.parentRef"
@ -160,6 +160,7 @@
</template> </template>
</Tabs> </Tabs>
</div> </div>
<ErrorPage v-else :errorTitle="errorTitle" :errorMessage="errorMessage" />
<QuickEntryModal <QuickEntryModal
v-if="showQuickEntryModal" v-if="showQuickEntryModal"
v-model="showQuickEntryModal" v-model="showQuickEntryModal"
@ -169,6 +170,7 @@
</template> </template>
<script setup> <script setup>
import ErrorPage from '@/components/ErrorPage.vue'
import Resizer from '@/components/Resizer.vue' import Resizer from '@/components/Resizer.vue'
import SidePanelLayout from '@/components/SidePanelLayout.vue' import SidePanelLayout from '@/components/SidePanelLayout.vue'
import Icon from '@/components/Icon.vue' import Icon from '@/components/Icon.vue'
@ -221,12 +223,27 @@ const showQuickEntryModal = ref(false)
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const errorTitle = ref('')
const errorMessage = ref('')
const organization = createDocumentResource({ const organization = createDocumentResource({
doctype: 'CRM Organization', doctype: 'CRM Organization',
name: props.organizationId, name: props.organizationId,
cache: ['organization', props.organizationId], cache: ['organization', props.organizationId],
fields: ['*'], fields: ['*'],
auto: true, auto: true,
onSuccess: () => {
errorTitle.value = ''
errorMessage.value = ''
},
onError: (err) => {
if (err.messages?.[0]) {
errorTitle.value = __('Not permitted')
errorMessage.value = __(err.messages?.[0])
} else {
router.push({ name: 'Organizations' })
}
},
}) })
async function updateField(fieldname, value) { async function updateField(fieldname, value) {