Skip to content

Commit d624045

Browse files
committed
Add OAuth-2 login via GitHub to query SlideRuleEarth membership #866
1 parent 200beb8 commit d624045

File tree

3 files changed

+88
-35
lines changed

3 files changed

+88
-35
lines changed

web-client/src/components/SrDeployConfig.vue

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import InputText from 'primevue/inputtext'
66
import Button from 'primevue/button'
77
import { useGitHubAuthStore } from '@/stores/githubAuthStore'
88
import { useDeployConfigStore } from '@/stores/deployConfigStore'
9+
import { useClusterReachability } from '@/composables/useClusterReachability'
910
import { storeToRefs } from 'pinia'
1011
1112
const githubAuthStore = useGitHubAuthStore()
@@ -15,6 +16,19 @@ const deployConfigStore = useDeployConfigStore()
1516
const { domain, clusterName, desiredVersion, currentNodes, canConnectNodes } =
1617
storeToRefs(deployConfigStore)
1718
19+
// Use deployableClusters directly from the store (exclude "*" wildcard from dropdown)
20+
const clusterList = computed(() =>
21+
(githubAuthStore.deployableClusters || []).filter((c) => c !== '*')
22+
)
23+
24+
// Check if deployableClusters contains wildcard "*" to enable editable mode
25+
const allowCustomCluster = computed(
26+
() => githubAuthStore.deployableClusters?.includes('*') ?? false
27+
)
28+
29+
// Use composable for cluster reachability
30+
const { refreshClusterReachability } = useClusterReachability(clusterList, domain)
31+
1832
async function refreshStatus() {
1933
deployConfigStore.resetStatus()
2034
if (clusterName.value) {
@@ -25,9 +39,6 @@ async function refreshStatus() {
2539
}
2640
}
2741
28-
// Use deployableClusters directly from the store
29-
const clusterList = computed(() => githubAuthStore.deployableClusters || [])
30-
3142
// Transform cluster options to include disabled state and status label
3243
const clusterOptionsWithStatus = computed(() => {
3344
return clusterList.value.map((c) => {
@@ -40,9 +51,12 @@ const clusterOptionsWithStatus = computed(() => {
4051
})
4152
})
4253
43-
// Refresh stack status for all clusters when dropdown opens
54+
// Refresh stack status and reachability for all clusters when dropdown opens
4455
async function refreshClusterStatus() {
45-
await deployConfigStore.refreshAllClusterStatus(clusterList.value)
56+
await Promise.all([
57+
deployConfigStore.refreshAllClusterStatus(clusterList.value),
58+
refreshClusterReachability()
59+
])
4660
}
4761
4862
// Set default cluster name when options become available
@@ -91,6 +105,7 @@ const isDomainDisabled = computed(() => !githubAuthStore.isOwner)
91105
<Select
92106
id="deploy-cluster"
93107
v-model="clusterName"
108+
:editable="allowCustomCluster"
94109
:options="clusterOptionsWithStatus"
95110
optionLabel="label"
96111
optionValue="value"

web-client/src/components/SrSysConfig.vue

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<script setup lang="ts">
2-
import { computed, watch, onMounted, ref } from 'vue'
2+
import { computed, watch, onMounted } from 'vue'
33
import Select from 'primevue/select'
44
import Button from 'primevue/button'
55
import { useGitHubAuthStore } from '@/stores/githubAuthStore'
66
import { useSysConfigStore } from '@/stores/sysConfigStore'
77
import { useLegacyJwtStore } from '@/stores/SrLegacyJwtStore'
8-
import { fetchServerVersionInfo as fetchVersionUtil } from '@/utils/fetchUtils'
8+
import { useClusterReachability } from '@/composables/useClusterReachability'
99
import { storeToRefs } from 'pinia'
1010
1111
const props = defineProps<{
@@ -44,33 +44,11 @@ const clusterOptions = computed(() => {
4444
return ['sliderule']
4545
})
4646
47-
// Track cluster reachability for disabling unreachable clusters in dropdown
48-
const clusterReachability = ref<Record<string, boolean>>({})
49-
50-
async function checkClusterReachability(clusterName: string): Promise<boolean> {
51-
const result = await fetchVersionUtil(clusterName, domain.value)
52-
return result.success
53-
}
54-
55-
async function refreshClusterReachability() {
56-
const clusters = clusterOptions.value
57-
const results: Record<string, boolean> = {}
58-
await Promise.all(
59-
clusters.map(async (c) => {
60-
results[c] = await checkClusterReachability(c)
61-
})
62-
)
63-
clusterReachability.value = results
64-
}
65-
66-
// Transform options to include disabled state for unreachable clusters
67-
const clusterOptionsWithState = computed(() => {
68-
return clusterOptions.value.map((c) => ({
69-
label: c,
70-
value: c,
71-
disabled: clusterReachability.value[c] === false
72-
}))
73-
})
47+
// Use composable for cluster reachability
48+
const { refreshClusterReachability, clusterOptionsWithState } = useClusterReachability(
49+
clusterOptions,
50+
domain
51+
)
7452
7553
// Available domain options - testsliderule.org only for org owners
7654
const domainOptions = computed(() => {
@@ -86,7 +64,7 @@ const isPublicCluster = computed(
8664
)
8765
8866
// Reset to public cluster
89-
async function resetToPublicCluster() {
67+
function resetToPublicCluster() {
9068
legacyJwtStore.clearAllJwts()
9169
sysConfigStore.$reset()
9270
// Set defaults: slideruleearth.io and sliderule
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { ref, computed, type Ref, type ComputedRef } from 'vue'
2+
import { fetchServerVersionInfo } from '@/utils/fetchUtils'
3+
4+
export interface ClusterOption {
5+
label: string
6+
value: string
7+
disabled: boolean
8+
}
9+
10+
export interface UseClusterReachabilityReturn {
11+
clusterReachability: Ref<Record<string, boolean>>
12+
checkClusterReachability: (_clusterName: string) => Promise<boolean>
13+
refreshClusterReachability: () => Promise<void>
14+
clusterOptionsWithState: ComputedRef<ClusterOption[]>
15+
}
16+
17+
/**
18+
* Composable for checking and tracking cluster reachability.
19+
*
20+
* @param clusters - Reactive ref to the list of cluster names
21+
* @param domain - Reactive ref to the current domain
22+
* @returns Object with reachability state and helper functions
23+
*/
24+
export function useClusterReachability(
25+
clusters: Ref<string[]> | ComputedRef<string[]>,
26+
domain: Ref<string>
27+
): UseClusterReachabilityReturn {
28+
const clusterReachability = ref<Record<string, boolean>>({})
29+
30+
async function checkClusterReachability(clusterName: string): Promise<boolean> {
31+
const result = await fetchServerVersionInfo(clusterName, domain.value)
32+
return result.success
33+
}
34+
35+
async function refreshClusterReachability(): Promise<void> {
36+
const clusterList = clusters.value
37+
const results: Record<string, boolean> = {}
38+
await Promise.all(
39+
clusterList.map(async (c) => {
40+
results[c] = await checkClusterReachability(c)
41+
})
42+
)
43+
clusterReachability.value = results
44+
}
45+
46+
const clusterOptionsWithState = computed<ClusterOption[]>(() => {
47+
return clusters.value.map((c) => ({
48+
label: c,
49+
value: c,
50+
disabled: clusterReachability.value[c] === false
51+
}))
52+
})
53+
54+
return {
55+
clusterReachability,
56+
checkClusterReachability,
57+
refreshClusterReachability,
58+
clusterOptionsWithState
59+
}
60+
}

0 commit comments

Comments
 (0)