Google Search Console - v1.0.0
Vue Components
Three Vue 3 components ship as source under resources/js/vue/. They mirror the React components API — same props, same states, same shared fetch client.
Requirements
- Vue 3+ (uses the Composition API with
<script setup>). - A bundler that compiles Vue SFCs (Vite, Webpack +
vue-loader, Turbopack, …). - An authenticated session — the endpoints run under
web+authmiddleware, so the browser must send the app's session cookie with the fetch.
Getting the sources
<script setup lang="ts">
import PerformanceCard from '@artisanpack-ui/google-search-console/vue/PerformanceCard.vue'
import TopQueriesTable from '@artisanpack-ui/google-search-console/vue/TopQueriesTable.vue'
import TopPagesTable from '@artisanpack-ui/google-search-console/vue/TopPagesTable.vue'
</script>
Or publish the sources with:
php artisan vendor:publish --tag=google-search-console-js
Then import from @/vendor/google-search-console/vue/….
<PerformanceCard />
<template>
<PerformanceCard :initial-days="28" />
</template>
Props
| Prop | Type | Default | Notes |
|---|---|---|---|
initialDays |
number |
28 |
Starting range. Built-in dropdown lets the user switch. |
siteUrl |
string | null |
null |
Override the configured site — ignored by the server-side controller, but useful if you point baseUrl at your own endpoint. |
baseUrl |
string |
/google-search-console |
Prefix for the JSON endpoint. Change if you moved the routes via google-search-console.routes.prefix. |
fetchImpl |
typeof fetch |
window.fetch |
Injectable fetch — swap for SSR or testing. |
Emits no events. Everything is prop-in / render-out.
<TopQueriesTable />
<TopQueriesTable :initial-days="28" :initial-limit="50" />
Same props as PerformanceCard plus initialLimit: number (default 50, clamped server-side to 1..1000).
<TopPagesTable />
<TopPagesTable :initial-days="28" :initial-limit="50" />
Same API as TopQueriesTable, rows keyed by page URL instead of query text.
State transitions
Every component tracks (using refs):
data: GscPerformanceData | GscTopQueriesData | GscTopPagesData | nullloading: booleanerrorCode: string | null— one ofunauthenticated,not_connected,base_not_installed,reporting_error, ornull.errorMessage: string | null
Rendered branches:
- Missing base — install-the-base CTA.
- Not connected — connect-a-Google-account CTA.
- Unauthenticated — sign-in CTA.
- Reporting error — the message from Google.
- No data — empty state.
- Success — the metrics / rows.
Aborting in-flight requests
Each component owns an AbortController that's aborted onUnmounted and on every new range selection — no zombie fetches. If you're calling the shared fetch functions directly (fetchGscPerformance etc.), pass a signal.
The shared fetch client
Identical to the React one — the .tsx and .vue files import from the same resources/js/shared/ layer. See Components/React#The shared fetch client for the API.
Call it directly if you want your own UI:
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { fetchGscPerformance, GscPerformanceError } from '@artisanpack-ui/google-search-console/shared/performance'
const data = ref<Awaited<ReturnType<typeof fetchGscPerformance>> | null>( null )
const error = ref<string | null>( null )
onMounted( async () => {
try {
data.value = await fetchGscPerformance( { days: 28 } )
} catch ( err ) {
if ( err instanceof GscPerformanceError ) {
error.value = err.message
}
}
} )
</script>
<template>
<div v-if="error">{{ error }}</div>
<div v-else-if="data">
Clicks: {{ data.totals.clicks }}
</div>
</template>
Styling
Same story as React — BEM classes, no styles applied. Add your own scoped or global styles.
Testing
With Vue Test Utils and a fake fetch:
import { mount } from '@vue/test-utils'
import PerformanceCard from '@artisanpack-ui/google-search-console/vue/PerformanceCard.vue'
const fakeFetch = async () => new Response(
JSON.stringify( {
range: { startDate: '2026-01-01', endDate: '2026-01-28' },
totals: { clicks: 42, impressions: 500, ctr: 0.084, position: 3.2 },
trend: [],
hasData: true,
} ),
{ status: 200, headers: { 'Content-Type': 'application/json' } },
)
test( 'renders totals from fake fetch', async () => {
const wrapper = mount( PerformanceCard, { props: { fetchImpl: fakeFetch } } )
await wrapper.vm.$nextTick()
expect( wrapper.text() ).toContain( '42' )
} )
Publishing sources into your app
php artisan vendor:publish --tag=google-search-console-js
Copies:
resources/js/vendor/google-search-console/react/— three.tsxfiles.resources/js/vendor/google-search-console/vue/— three.vuefiles.resources/js/vendor/google-search-console/shared/— the fetch client.