Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
7864286
Port map components to typescript
irees Oct 7, 2025
4a0e725
Port departures component to typescript
irees Oct 7, 2025
c6a1c32
Port stop-departures to typescript
irees Oct 7, 2025
4d3bc54
Port multi-service-levels to typescript
irees Oct 7, 2025
f60883e
Port rsp-viewer to typescript
irees Oct 7, 2025
4d7b5d5
Port feeds-table to typescript
irees Oct 7, 2025
7b49377
Port operators-table to typescript
irees Oct 7, 2025
23a2d81
Convert feed-version-table to typescript
irees Oct 7, 2025
21e0e2b
Port feed-rt-download to typescript
irees Oct 7, 2025
9a7c118
Port map-search to typescript
irees Oct 7, 2025
cf634ee
Port map-search to typescript, with fixes
irees Oct 8, 2025
c506a6c
Port places.vue to typescript
irees Oct 8, 2025
e603e79
Port data-export and census-viewer to typescript
irees Oct 8, 2025
f4455e9
Port stop-table to typescript
irees Oct 8, 2025
7e7a352
Port route-table to typescript
irees Oct 8, 2025
9190ab6
Port headway-viewer to typescript
irees Oct 8, 2025
c708de6
Convert components to typescript
irees Oct 10, 2025
03e5966
Convert to typescript
irees Oct 10, 2025
7ebd310
Convert to typescript
irees Oct 10, 2025
f954570
Convert to typescript
irees Oct 10, 2025
9931afd
Convert to typescript
irees Oct 10, 2025
9fcd25a
Convert to typescript
irees Oct 10, 2025
1cd74a6
Convert to typescript
irees Oct 10, 2025
f307f1a
More conversions
irees Oct 10, 2025
d81f7a2
Merge branch 'main' into typescript-ports
irees Oct 11, 2025
f51b4d7
Port to typescript
irees Oct 11, 2025
7961ceb
Port feed-version-download.vue to typescript
irees Oct 11, 2025
e960c07
Port feed-info.vue to typescript
irees Oct 11, 2025
8cf450b
Fix filters.ts issues
irees Oct 11, 2025
ae1635e
Port agency-table.vue to typescript
irees Oct 11, 2025
7900721
Port modal.vue to typescript
irees Oct 11, 2025
f7a0e68
Port modal.vue to typescript
irees Oct 11, 2025
7aa9931
Port geolocation.vue to typescript
irees Oct 11, 2025
61c12d8
Port file-info-table.vue to typescript
irees Oct 11, 2025
fc07a00
Port feed-version-import-status.vue to typescript
irees Oct 11, 2025
b31a1a9
Port route-type-select.vue to typescript
irees Oct 11, 2025
eae69bc
Port route-type-select to typescript
irees Oct 11, 2025
376e438
Port search-bar.vue to tyepscript
irees Oct 11, 2025
8903e77
Port map-route-list.vue to typescript
irees Oct 11, 2025
5a17268
Port login-gate.vue to typescript
irees Oct 11, 2025
a946221
Port login-gate.vue to typescript
irees Oct 11, 2025
b93b633
Port check-single.vue to typescript
irees Oct 11, 2025
e05f565
Port feed-version-active-status.vue to typescript
irees Oct 11, 2025
7992a7a
Port geojson-downloader.vue to typescript
irees Oct 11, 2025
982948e
Start using geojson types directly
irees Oct 11, 2025
4f2c162
Use geojson types directly
irees Oct 11, 2025
99f89d9
Do not use $filters
irees Oct 11, 2025
b19a93f
Convert title.vue to typescript
irees Oct 11, 2025
cc003ed
Port more components to typescript
irees Oct 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"@types/cytoscape": "3.21.9",
"@types/cytoscape-fcose": "2.2.4",
"@types/d3-scale-chromatic": "3.1.0",
"@types/geojson": "7946.0.16",
"@types/jsdom": "21.1.7",
"@types/mapbox__mapbox-gl-draw": "1.4.8",
"@types/node": "22.13.10",
Expand Down
129 changes: 94 additions & 35 deletions src/runtime/components/agency-table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</tl-msg-error>
<div v-else>
<tl-search-bar v-model="search" placeholder="Filter Agencies" />
<o-loading v-model:active="$apollo.loading" :full-page="false" />
<o-loading v-model:active="loading" :full-page="false" />
<div class="table-container">
<table class="table is-striped is-fullwidth">
<thead>
Expand All @@ -31,47 +31,106 @@
</div>
</template>

<script>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useQuery } from '@vue/apollo-composable'
import { gql } from 'graphql-tag'
import TableViewerMixin from './table-viewer-mixin'

const q = gql`
query ($feed_version_sha1: String, $limit: Int=100, $after: Int, $search: String) {
entities: agencies(after: $after, limit: $limit, where: {feed_version_sha1: $feed_version_sha1, search: $search}) {
id
agency_id
agency_name
agency_url
feed_onestop_id
feed_version_sha1
}
// TypeScript interfaces
interface Agency {
id: number
agency_id: string
agency_name: string
agency_url?: string | null
feed_onestop_id: string
feed_version_sha1: string
}

interface AgenciesQueryResponse {
entities: Agency[]
}

// Props
interface Props {
fvid?: string
limit?: number
}
`

export default {
mixins: [TableViewerMixin],
props: {
fvid: { type: String, default () { return '' } }
},
data () {
return {
sortField: 'agency_id',
sortOrder: 'asc'
const props = withDefaults(defineProps<Props>(), {
fvid: '',
limit: 100
})

// Reactive state
const search = ref<string>('')
const hasMore = ref(false)
const prevAfter = ref<number | null>(null)
const sortField = ref('agency_id')
const sortOrder = ref('asc')
const error = ref<string | null>(null)

// GraphQL query
const agenciesQuery = gql`
query ($feed_version_sha1: String, $limit: Int = 100, $after: Int, $search: String) {
entities: agencies(after: $after, limit: $limit, where: {feed_version_sha1: $feed_version_sha1, search: $search}) {
id
agency_id
agency_name
agency_url
feed_onestop_id
feed_version_sha1
}
},
apollo: {
entities: {
client: 'transitland',
query: q,
variables () {
}
`

// Apollo query
const { result, loading, error: queryError, fetchMore } = useQuery<AgenciesQueryResponse>(
agenciesQuery,
() => ({
search: search.value,
feed_version_sha1: props.fvid,
limit: props.limit
}),
{
clientId: 'transitland'
}
)

// Watch for query errors
import { watch } from 'vue'
watch(queryError, (newError) => {
if (newError) {
error.value = newError.message
}
})

// Computed properties
const entities = computed<Agency[]>(() => result.value?.entities || [])

// Methods
const showAll = async () => {
const newLimit = 1000
const lastId = entities.value.length > 0 ? entities.value[entities.value.length - 1].id : 0

try {
await fetchMore({
variables: {
after: lastId,
limit: newLimit
},
updateQuery: (previousResult, { fetchMoreResult }) => {
if (fetchMoreResult.entities.length >= newLimit) {
hasMore.value = true
} else {
hasMore.value = false
}
return {
search: this.search,
feed_version_sha1: this.fvid,
limit: this.limit
entities: [...previousResult.entities, ...fetchMoreResult.entities]
}
},
error (e) { this.error = e }
}
}
})
} catch (err) {
error.value = err instanceof Error ? err.message : 'Failed to load more agencies'
}
}
</script>
92 changes: 43 additions & 49 deletions src/runtime/components/api-example.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,61 +50,55 @@
</div>
</template>

<script>
<script setup lang="ts">
import { ref } from 'vue'
import { useToastNotification } from '../composables/useToastNotification'

export default {
name: 'ApiExample',
props: {
title: {
type: String,
default: 'API Example'
},
description: {
type: String,
default: 'Use this endpoint to query the API:'
},
apiUrl: {
type: String,
required: true
},
learnMoreUrl: {
type: String,
default: null
}
},
data () {
return {
copying: false
}
},
methods: {
async copyToClipboard () {
if (!this.apiUrl) return
// TypeScript interfaces
interface Props {
title?: string
description?: string
apiUrl: string
learnMoreUrl?: string | null
}

const props = withDefaults(defineProps<Props>(), {
title: 'API Example',
description: 'Use this endpoint to query the API:',
learnMoreUrl: null
})

// Reactive data
const copying = ref<boolean>(false)

this.copying = true
// Get toast notification composable
const { showToast } = useToastNotification()

try {
await navigator.clipboard.writeText(this.apiUrl)
useToastNotification().showToast('API URL copied to clipboard')
} catch (err) {
console.error('Copy to clipboard failed:', err)
// Fallback for older browsers
const textArea = document.createElement('textarea')
textArea.value = this.apiUrl
document.body.appendChild(textArea)
textArea.select()
document.execCommand('copy')
document.body.removeChild(textArea)
useToastNotification().showToast('API URL copied to clipboard')
}
// Methods
const copyToClipboard = async (): Promise<void> => {
if (!props.apiUrl) return

// Reset button text after a short delay
setTimeout(() => {
this.copying = false
}, 1500)
}
copying.value = true

try {
await navigator.clipboard.writeText(props.apiUrl)
showToast('API URL copied to clipboard')
} catch (err) {
console.error('Copy to clipboard failed:', err)
// Fallback for older browsers
const textArea = document.createElement('textarea')
textArea.value = props.apiUrl
document.body.appendChild(textArea)
textArea.select()
document.execCommand('copy')
document.body.removeChild(textArea)
showToast('API URL copied to clipboard')
}

// Reset button text after a short delay
setTimeout(() => {
copying.value = false
}, 1500)
}
</script>

Expand Down
49 changes: 30 additions & 19 deletions src/runtime/components/associated-operators.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,35 @@
</div>
</template>

<script>
export default {
props: {
associatedOperators: { type: Array, default () { return [] } }
},
data () {
return {
showAllRows: false
}
},
computed: {
associatedOperatorsToDisplay () {
if (this.showAllRows) {
return this.associatedOperators
} else {
return this.associatedOperators.slice(0, 5)
}
}
}
<script setup lang="ts">
import { ref, computed } from 'vue'

// TypeScript interfaces
interface Operator {
id: number
name: string
short_name?: string | null
onestop_id: string
}

// Props
interface Props {
associatedOperators?: Operator[]
}

const props = withDefaults(defineProps<Props>(), {
associatedOperators: () => []
})

// Reactive state
const showAllRows = ref(false)

// Computed properties
const associatedOperatorsToDisplay = computed((): Operator[] => {
if (showAllRows.value) {
return props.associatedOperators
} else {
return props.associatedOperators.slice(0, 5)
}
})
</script>
Loading