%PDF- %PDF-
Direktori : /home/forge/api-takeaseat.eco-n-tech.co.uk/vendor/laravel/nova/resources/js/views/ |
Current File : //home/forge/api-takeaseat.eco-n-tech.co.uk/vendor/laravel/nova/resources/js/views/Lens.vue |
<template> <loading-view :loading="initialLoading" :dusk="lens + '-lens-component'"> <custom-lens-header class="mb-3" :resource-name="resourceName" /> <div v-if="shouldShowCards"> <cards v-if="smallCards.length > 0" :cards="smallCards" class="mb-3" :resource-name="resourceName" :lens="lens" /> <cards v-if="largeCards.length > 0" :cards="largeCards" size="large" :resource-name="resourceName" :lens="lens" /> </div> <heading v-if="resourceResponse" class="mb-3"> <router-link :to="{ name: 'index', params: { resourceName: resourceName, }, }" class="no-underline text-primary font-bold dim" data-testid="lens-back" >←</router-link > <span class="px-2 text-70">/</span> {{ lenseName }} </heading> <card> <div class="py-3 flex items-center border-b border-50"> <div class="px-3" v-if="shouldShowCheckBoxes"> <!-- Select All --> <dropdown dusk="select-all-dropdown" placement="bottom-end" class="-mx-2" > <dropdown-trigger class="px-2"> <fake-checkbox :checked="selectAllChecked" /> </dropdown-trigger> <dropdown-menu slot="menu" direction="ltr" width="250"> <div class="p-4"> <ul class="list-reset"> <li class="flex items-center mb-4"> <checkbox-with-label :checked="selectAllChecked" @input="toggleSelectAll" > {{ __('Select All') }} </checkbox-with-label> </li> <li class="flex items-center" v-if="allMatchingResourceCount > 0" > <checkbox-with-label dusk="select-all-matching-button" :checked="selectAllMatchingChecked" @input="toggleSelectAllMatching" > <template> <span class="mr-1"> {{ __('Select All Matching') }} ({{ allMatchingResourceCount }}) </span> </template> </checkbox-with-label> </li> </ul> </div> </dropdown-menu> </dropdown> </div> <div class="flex items-center ml-auto px-3"> <!-- Action Selector --> <action-selector v-if="selectedResources.length > 0 || haveStandaloneActions" :resource-name="resourceName" :actions="availableActions" :pivot-actions="pivotActions" :pivot-name="pivotName" :selected-resources="selectedResourcesForActionSelector" :endpoint="lensActionEndpoint" :query-string="{ currentSearch, encodedFilters, currentTrashed, viaResource, viaResourceId, viaRelationship, }" @actionExecuted="getResources" /> <filter-menu :resourceName="resourceName" :soft-deletes="softDeletes" :via-resource="viaResource" :via-has-one="viaHasOne" :trashed="trashed" :per-page="perPage" :per-page-options=" perPageOptions || resourceInformation.perPageOptions " :show-trashed-option=" authorizedToForceDeleteAnyResources || authorizedToRestoreAnyResources " :lens="lens" @clear-selected-filters="clearSelectedFilters(lens)" @filter-changed="filterChanged" @trashed-changed="trashedChanged" @per-page-changed="updatePerPageChanged" /> <delete-menu v-if="shouldShowDeleteMenu" dusk="delete-menu" :soft-deletes="softDeletes" :resources="resources" :selected-resources="selectedResources" :via-many-to-many="viaManyToMany" :all-matching-resource-count="allMatchingResourceCount" :all-matching-selected="selectAllMatchingChecked" :authorized-to-delete-selected-resources=" authorizedToDeleteSelectedResources " :authorized-to-force-delete-selected-resources=" authorizedToForceDeleteSelectedResources " :authorized-to-delete-any-resources="authorizedToDeleteAnyResources" :authorized-to-force-delete-any-resources=" authorizedToForceDeleteAnyResources " :authorized-to-restore-selected-resources=" authorizedToRestoreSelectedResources " :authorized-to-restore-any-resources=" authorizedToRestoreAnyResources " @deleteSelected="deleteSelectedResources" @deleteAllMatching="deleteAllMatchingResources" @forceDeleteSelected="forceDeleteSelectedResources" @forceDeleteAllMatching="forceDeleteAllMatchingResources" @restoreSelected="restoreSelectedResources" @restoreAllMatching="restoreAllMatchingResources" @close="deleteModalOpen = false" /> </div> </div> <loading-view :loading="loading"> <div v-if="!resources.length" class="flex justify-center items-center px-6 py-8" > <div class="text-center"> <svg class="mb-3" xmlns="http://www.w3.org/2000/svg" width="65" height="51" viewBox="0 0 65 51" > <path fill="#A8B9C5" d="M56 40h2c.552285 0 1 .447715 1 1s-.447715 1-1 1h-2v2c0 .552285-.447715 1-1 1s-1-.447715-1-1v-2h-2c-.552285 0-1-.447715-1-1s.447715-1 1-1h2v-2c0-.552285.447715-1 1-1s1 .447715 1 1v2zm-5.364125-8H38v8h7.049375c.350333-3.528515 2.534789-6.517471 5.5865-8zm-5.5865 10H6c-3.313708 0-6-2.686292-6-6V6c0-3.313708 2.686292-6 6-6h44c3.313708 0 6 2.686292 6 6v25.049375C61.053323 31.5511 65 35.814652 65 41c0 5.522847-4.477153 10-10 10-5.185348 0-9.4489-3.946677-9.950625-9zM20 30h16v-8H20v8zm0 2v8h16v-8H20zm34-2v-8H38v8h16zM2 30h16v-8H2v8zm0 2v4c0 2.209139 1.790861 4 4 4h12v-8H2zm18-12h16v-8H20v8zm34 0v-8H38v8h16zM2 20h16v-8H2v8zm52-10V6c0-2.209139-1.790861-4-4-4H6C3.790861 2 2 3.790861 2 6v4h52zm1 39c4.418278 0 8-3.581722 8-8s-3.581722-8-8-8-8 3.581722-8 8 3.581722 8 8 8z" /> </svg> <h3 class="text-base text-80 font-normal mb-6"> {{ __('No :resource matched the given criteria.', { resource: resourceInformation.label.toLowerCase(), }) }} </h3> <create-resource-button classes="btn btn-sm btn-outline" :singular-name="singularName" :resource-name="resourceName" :via-resource="viaResource" :via-resource-id="viaResourceId" :via-relationship="viaRelationship" :relationship-type="relationshipType" :authorized-to-create="authorizedToCreate && !resourceIsFull" :authorized-to-relate="authorizedToRelate" /> </div> </div> <!-- Resource Table --> <div class="overflow-hidden overflow-x-auto relative"> <resource-table :authorized-to-relate="authorizedToRelate" :resource-name="resourceName" :resources="resources" :singular-name="singularName" :selected-resources="selectedResources" :selected-resource-ids="selectedResourceIds" :actions-are-available="allActions.length > 0" :actions-endpoint="lensActionEndpoint" :should-show-checkboxes="shouldShowCheckBoxes" :via-resource="viaResource" :via-resource-id="viaResourceId" :via-relationship="viaRelationship" :relationship-type="relationshipType" :update-selection-status="updateSelectionStatus" @order="orderByField" @reset-order-by="resetOrderBy" @delete="deleteResources" @restore="restoreResources" @actionExecuted="getResources" ref="resourceTable" /> </div> <!-- Pagination --> <component :is="paginationComponent" v-if="resourceResponse && resources.length > 0" :next="hasNextPage" :previous="hasPreviousPage" @load-more="loadMore" @page="selectPage" :pages="totalPages" :page="currentPage" :per-page="perPage" :resource-count-label="resourceCountLabel" :current-resource-count="resources.length" :all-matching-resource-count="allMatchingResourceCount" > <span v-if="resourceCountLabel" class="text-sm text-80 px-4" :class="{ 'ml-auto': paginationComponent == 'pagination-links', }" > {{ resourceCountLabel }} </span> </component> </loading-view> </card> </loading-view> </template> <script> import { HasCards, Deletable, Errors, Filterable, Minimum, Paginatable, PerPageable, InteractsWithQueryString, InteractsWithResourceInformation, } from 'laravel-nova' import HasActions from '@/mixins/HasActions' import { CancelToken, Cancel } from 'axios' export default { mixins: [ HasActions, HasCards, Deletable, Filterable, Paginatable, PerPageable, InteractsWithResourceInformation, InteractsWithQueryString, ], metaInfo() { return { title: this.lenseName, } }, props: { resourceName: { type: String, required: true, }, viaResource: { default: '', }, viaResourceId: { default: '', }, viaRelationship: { default: '', }, relationshipType: { type: String, default: '', }, lens: { type: String, required: true, }, }, data: () => ({ canceller: null, initialLoading: true, loading: true, resourceResponse: null, resources: [], softDeletes: false, selectedResources: [], selectAllMatchingResources: false, allMatchingResourceCount: 0, hasId: false, deleteModalOpen: false, actionValidationErrors: new Errors(), authorizedToRelate: false, orderBy: '', orderByDirection: '', trashed: '', // Load More Pagination currentPageLoadMore: null, }), /** * Mount the component and retrieve its initial data. */ async created() { if (Nova.missingResource(this.resourceName)) return this.$router.push({ name: '404' }) this.initializeSearchFromQueryString() this.initializePerPageFromQueryString() this.initializeTrashedFromQueryString() this.initializeOrderingFromQueryString() await this.initializeFilters(this.lens) this.getResources() // this.getAuthorizationToRelate() this.getActions() this.initialLoading = false this.$watch( () => { return ( this.lens + this.resourceName + this.encodedFilters + this.currentSearch + this.currentPage + this.currentPerPage + this.currentOrderBy + this.currentOrderByDirection + this.currentTrashed ) }, () => { if (this.canceller !== null) this.canceller() this.getResources() } ) }, watch: { $route(to, from) { if ( to.params.resourceName === from.params.resourceName && to.params.lens === from.params.lens ) { this.initializeState(this.lens) } else { this.initializeFilters(this.lens) this.getActions() } }, }, methods: { selectAllResources() { this.selectedResources = this.resources.slice(0) }, toggleSelectAll() { if (this.selectAllChecked) return this.clearResourceSelections() this.selectAllResources() }, toggleSelectAllMatching() { if (!this.selectAllMatchingResources) { this.selectAllResources() this.selectAllMatchingResources = true return } this.selectAllMatchingResources = false }, /* * Update the resource selection status */ updateSelectionStatus(resource) { if (!_(this.selectedResources).includes(resource)) return this.selectedResources.push(resource) const index = this.selectedResources.indexOf(resource) if (index > -1) return this.selectedResources.splice(index, 1) }, /** * Get the resources based on the current page, search, filters, etc. */ getResources() { this.loading = true this.$nextTick(() => { this.clearResourceSelections() return Minimum( Nova.request().get( '/nova-api/' + this.resourceName + '/lens/' + this.lens, { params: this.resourceRequestQueryString, cancelToken: new CancelToken(canceller => { this.canceller = canceller }), } ), 300 ) .then(({ data }) => { this.resources = [] this.resourceResponse = data this.resources = data.resources this.softDeletes = data.softDeletes this.perPage = data.per_page this.hasId = data.hasId this.loading = false this.getAllMatchingResourceCount() Nova.$emit('resources-loaded') }) .catch(e => { if (e instanceof Cancel) { return } throw e }) }) }, /** * Get the actions available for the current resource. */ getActions() { this.actions = [] this.pivotActions = null Nova.request() .get(`/nova-api/${this.resourceName}/lens/${this.lens}/actions`, { params: { viaResource: this.viaResource, viaResourceId: this.viaResourceId, viaRelationship: this.viaRelationship, relationshipType: this.relationshipType, display: 'index', }, }) .then(response => { this.actions = response.data.actions this.pivotActions = response.data.pivotActions }) }, /** * Clear the selected resouces and the "select all" states. */ clearResourceSelections() { this.selectAllMatchingResources = false this.selectedResources = [] }, /** * Get the count of all of the matching resources. */ getAllMatchingResourceCount() { Nova.request() .get( '/nova-api/' + this.resourceName + '/lens/' + this.lens + '/count', { params: this.resourceRequestQueryString, } ) .then(response => { this.allMatchingResourceCount = response.data.count }) }, /** * Sort the resources by the given field. */ orderByField(field) { let direction = this.currentOrderByDirection == 'asc' ? 'desc' : 'asc' if (this.currentOrderBy != field.sortableUriKey) { direction = 'asc' } this.updateQueryString({ [this.orderByParameter]: field.sortableUriKey, [this.orderByDirectionParameter]: direction, }) }, /** * Reset the order by to its default state */ resetOrderBy(field) { this.updateQueryString({ [this.orderByParameter]: field.sortableUriKey, [this.orderByDirectionParameter]: null, }) }, /** * Sync the current search value from the query string. */ initializeSearchFromQueryString() { this.search = this.currentSearch }, /** * Sync the current order by values from the query string. */ initializeOrderingFromQueryString() { this.orderBy = this.currentOrderBy this.orderByDirection = this.currentOrderByDirection }, /** * Sync the trashed state values from the query string. */ initializeTrashedFromQueryString() { this.trashed = this.currentTrashed }, /** * Update the trashed constraint for the resource listing. */ trashedChanged(trashedStatus) { this.trashed = trashedStatus this.updateQueryString({ [this.trashedParameter]: this.trashed }) }, /** * Update the per page parameter in the query string */ updatePerPageChanged(perPage) { this.perPage = perPage this.perPageChanged() }, /** * Load more resources. */ loadMore() { if (this.currentPageLoadMore === null) { this.currentPageLoadMore = this.currentPage } this.currentPageLoadMore = this.currentPageLoadMore + 1 return Minimum( Nova.request().get( '/nova-api/' + this.resourceName + '/lens/' + this.lens, { params: { ...this.resourceRequestQueryString, page: this.currentPageLoadMore, // We do this to override whatever page number is in the URL }, } ), 300 ).then(({ data }) => { this.resourceResponse = data this.resources = [...this.resources, ...data.resources] this.getAllMatchingResourceCount() Nova.$emit('resources-loaded') }) }, /** * Select the next page. */ selectPage(page) { this.updateQueryString({ [this.pageParameter]: page }) }, /** * Sync the per page values from the query string. */ initializePerPageFromQueryString() { this.perPage = this.$route.query[this.perPageParameter] || this.resourceInformation.perPageOptions[0] }, }, computed: { /** * Get the endpoint for this resource's actions. */ lensActionEndpoint() { return `/nova-api/${this.resourceName}/lens/${this.lens}/action` }, /** * Get the name of the search query string variable. */ searchParameter() { return this.resourceName + '_search' }, /** * Get the name of the order by query string variable. */ orderByParameter() { return this.resourceName + '_order' }, /** * Get the name of the order by direction query string variable. */ orderByDirectionParameter() { return this.resourceName + '_direction' }, /** * Get the name of the trashed constraint query string variable. */ trashedParameter() { return this.resourceName + '_trashed' }, /** * Get the name of the per page query string variable. */ perPageParameter() { return this.resourceName + '_per_page' }, /** * Get the name of the page query string variable. */ pageParameter() { return this.resourceName + '_page' }, /** * Build the resource request query string. */ resourceRequestQueryString() { return { search: this.currentSearch, filters: this.encodedFilters, orderBy: this.currentOrderBy, orderByDirection: this.currentOrderByDirection, perPage: this.currentPerPage, page: this.currentPage, viaResource: this.viaResource, viaResourceId: this.viaResourceId, // viaRelationship: this.viaRelationship, viaResourceRelationship: this.viaResourceRelationship, relationshipType: this.relationshipType, } }, /** * Determine if all resources are selected. */ selectAllChecked() { return this.selectedResources.length == this.resources.length }, /** * Determine if all matching resources are selected. */ selectAllMatchingChecked() { return ( this.selectedResources.length == this.resources.length && this.selectAllMatchingResources ) }, /** * Get the IDs for the selected resources. */ selectedResourceIds() { return _.map(this.selectedResources, resource => resource.id.value) }, /** * Get the current search value from the query string. */ currentSearch() { return this.$route.query[this.searchParameter] || '' }, /** * Get the current order by value from the query string. */ currentOrderBy() { return this.$route.query[this.orderByParameter] || '' }, /** * Get the current order by direction from the query string. */ currentOrderByDirection() { return this.$route.query[this.orderByDirectionParameter] || 'desc' }, /** * Get the current trashed constraint value from the query string. */ currentTrashed() { return this.$route.query[this.trashedParameter] || '' }, /** * Determine if the current resource listing is via a many-to-many relationship. */ viaManyToMany() { return ( this.relationshipType == 'belongsToMany' || this.relationshipType == 'morphToMany' ) }, /** * Determine if the resource / relationship is "full". */ resourceIsFull() { return this.viaHasOne && this.resources.length > 0 }, /** * Determine if the current resource listing is via a has-one relationship. */ viaHasOne() { return ( this.relationshipType == 'hasOne' || this.relationshipType == 'morphOne' ) }, /** * Get the singular name for the resource */ singularName() { return this.resourceInformation.singularLabel }, /** * Determine if there are any resources for the view */ hasResources() { return Boolean(this.resources.length > 0) }, /** * Determine if the resource should show any cards */ shouldShowCards() { return this.cards.length > 0 }, /** * Get the endpoint for this resource's metrics. */ cardsEndpoint() { return `/nova-api/${this.resourceName}/lens/${this.lens}/cards` }, /** * Determine whether to show the selection checkboxes for resources */ shouldShowCheckBoxes() { return ( Boolean(this.hasResources && !this.viaHasOne) && Boolean( this.actionsAreAvailable || this.authorizedToDeleteAnyResources || this.canShowDeleteMenu ) ) }, /** * Determine whether the delete menu should be shown to the user */ shouldShowDeleteMenu() { return ( Boolean(this.selectedResources.length > 0) && this.canShowDeleteMenu ) }, /** * Determine if any selected resources may be deleted. */ authorizedToDeleteSelectedResources() { return Boolean( _.find(this.selectedResources, resource => resource.authorizedToDelete) ) }, /** * Determine if any selected resources may be force deleted. */ authorizedToForceDeleteSelectedResources() { return Boolean( _.find( this.selectedResources, resource => resource.authorizedToForceDelete ) ) }, /** * Determine if the user is authorized to delete any listed resource. */ authorizedToDeleteAnyResources() { return ( this.resources.length > 0 && Boolean(_.find(this.resources, resource => resource.authorizedToDelete)) ) }, /** * Determine if the user is authorized to force delete any listed resource. */ authorizedToForceDeleteAnyResources() { return ( this.resources.length > 0 && Boolean( _.find(this.resources, resource => resource.authorizedToForceDelete) ) ) }, /** * Determine if any selected resources may be restored. */ authorizedToRestoreSelectedResources() { return Boolean( _.find(this.selectedResources, resource => resource.authorizedToRestore) ) }, /** * Determine if the user is authorized to restore any listed resource. */ authorizedToRestoreAnyResources() { return ( this.resources.length > 0 && Boolean( _.find(this.resources, resource => resource.authorizedToRestore) ) ) }, /** * Determine whether the user is authorized to perform actions on the delete menu */ canShowDeleteMenu() { return ( this.hasId && Boolean( this.authorizedToDeleteSelectedResources || this.authorizedToForceDeleteSelectedResources || this.authorizedToDeleteAnyResources || this.authorizedToForceDeleteAnyResources || this.authorizedToRestoreSelectedResources || this.authorizedToRestoreAnyResources ) ) }, /** * Return the currently encoded filter string from the store */ encodedFilters() { return this.$store.getters[`${this.resourceName}/currentEncodedFilters`] }, /** * Return the initial encoded filters from the query string */ initialEncodedFilters() { return this.$route.query[this.filterParameter] || '' }, paginationComponent() { return `pagination-${Nova.config['pagination'] || 'links'}` }, hasNextPage() { return Boolean( this.resourceResponse && this.resourceResponse.next_page_url ) }, hasPreviousPage() { return Boolean( this.resourceResponse && this.resourceResponse.prev_page_url ) }, totalPages() { return Math.ceil(this.allMatchingResourceCount / this.currentPerPage) }, /** * Return the resource count label */ resourceCountLabel() { const first = this.perPage * (this.currentPage - 1) return ( this.resources.length && `${first + 1}-${first + this.resources.length} ${this.__('of')} ${ this.allMatchingResourceCount }` ) }, /** * Get the current per page value from the query string. */ currentPerPage() { return this.perPage }, /** * The per-page options configured for this resource. */ perPageOptions() { if (this.resourceResponse) { return this.resourceResponse.per_page_options } }, /** * The Lense name. */ lenseName() { if (this.resourceResponse) { return this.resourceResponse.name } }, }, } </script>