247 lines
8.1 KiB
Vue

<template>
<div class="bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 shadow-sm">
<div class="p-6">
<!-- Enhanced URL Input Section -->
<div class="flex items-center gap-3 mb-6">
<FormKit
type="select"
v-model="httpMethod"
:options="httpMethods"
outer-class="!mb-0 w-32 flex-shrink-0"
inner-class="!mb-0 font-medium"
/>
<div class="flex-1 relative">
<FormKit
type="text"
v-model="requestUrl"
placeholder="Enter request URL (e.g., https://httpbin.org/get)"
outer-class="!mb-0"
inner-class="!mb-0 pr-10 !bg-white dark:!bg-gray-800"
/>
<!-- Variable indicator -->
<div v-if="urlVariables.length > 0" class="absolute right-3 top-1/2 transform -translate-y-1/2">
<rs-button
variant="text"
size="sm"
@click="showVariablePreview = !showVariablePreview"
class="p-1 text-blue-500 hover:text-blue-600 transition-colors"
:title="`${urlVariables.length} variable(s) found`"
>
<Icon name="ic:outline-code" size="16" />
</rs-button>
</div>
</div>
<rs-button
variant="primary"
@click="handleSendRequest"
:loading="isLoading"
class="px-8 py-2.5 flex-shrink-0 font-medium"
>
<Icon name="ic:outline-send" size="16" class="mr-2" />
Send
</rs-button>
</div>
<!-- Enhanced Variable Preview -->
<div v-if="showVariablePreview && urlVariables.length > 0" class="mb-6 p-4 bg-blue-50 dark:bg-blue-900/20 rounded-lg border border-blue-200 dark:border-blue-800">
<div class="flex items-center gap-2 mb-3">
<Icon name="ic:outline-code" size="16" class="text-blue-600 dark:text-blue-400" />
<h4 class="text-sm font-medium text-blue-900 dark:text-blue-100">Variables in URL</h4>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-2">
<div
v-for="variable in urlVariables"
:key="variable.name"
class="flex items-center gap-2 text-sm p-2 bg-white dark:bg-blue-900/40 rounded border"
>
<span class="font-mono text-blue-700 dark:text-blue-300 font-medium" v-text="formatVariableName(variable.name)"></span>
<Icon
:name="variable.found ? 'ic:outline-check' : 'ic:outline-warning'"
size="14"
:class="variable.found ? 'text-green-500' : 'text-yellow-500'"
/>
<span :class="variable.found ? 'text-green-700 dark:text-green-300' : 'text-yellow-700 dark:text-yellow-300'" class="truncate">
{{ variable.found ? variable.value : 'Not defined' }}
</span>
</div>
</div>
</div>
<!-- Enhanced Environment Indicator -->
<div v-if="currentEnvironment" class="mb-6 flex items-center gap-2 p-3 bg-green-50 dark:bg-green-900/20 rounded-lg border border-green-200 dark:border-green-800">
<Icon name="ic:outline-layers" size="16" class="text-green-600 dark:text-green-400" />
<span class="text-sm text-green-800 dark:text-green-200">
Using environment: <span class="font-medium">{{ currentEnvironment.name }}</span>
</span>
</div>
<!-- Enhanced Tabs -->
<div class="border-b border-gray-200 dark:border-gray-700">
<nav class="-mb-px flex space-x-8 overflow-x-auto">
<button
v-for="tab in tabs"
:key="tab.id"
@click="activeTab = tab.id"
:class="[
activeTab === tab.id
? 'border-primary-500 text-primary-600 dark:text-primary-400'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300',
'whitespace-nowrap py-3 px-1 border-b-2 font-medium text-sm flex items-center gap-2 flex-shrink-0'
]"
>
<Icon :name="tab.icon" size="16" />
{{ tab.label }}
<rs-badge v-if="tab.count" variant="secondary" size="sm">{{ tab.count }}</rs-badge>
</button>
</nav>
</div>
<!-- Enhanced Tab Content -->
<div class="py-6 overflow-x-auto">
<!-- Params Tab -->
<ParamsTab v-if="activeTab === 'params'" :params="requestParams" />
<!-- Headers Tab -->
<HeadersTab v-if="activeTab === 'headers'" :headers="requestHeaders" />
<!-- Auth Tab -->
<AuthTab v-if="activeTab === 'auth'" :auth="requestAuth" />
<!-- Body Tab -->
<BodyTab v-if="activeTab === 'body'" :body="requestBody" />
</div>
</div>
</div>
</template>
<script setup>
import ParamsTab from './tabs/ParamsTab.vue'
import HeadersTab from './tabs/HeadersTab.vue'
import AuthTab from './tabs/AuthTab.vue'
import BodyTab from './tabs/BodyTab.vue'
const { sendRequest: sendRequestUtil } = useApiRequest()
const { processRequest, findVariables, currentEnvironment } = useVariableSubstitution()
const {
activeTab,
httpMethod,
requestUrl,
isLoading,
requestParams,
requestHeaders,
requestAuth,
requestBody,
response,
requestHistory,
requestName,
httpMethods,
showNotification
} = useApiPlatform()
const showVariablePreview = ref(false)
// Enhanced tab configuration
const tabs = computed(() => [
{
id: 'params',
label: 'Params',
icon: 'ic:outline-tune',
count: requestParams.value.filter(p => p.active && p.key).length
},
{
id: 'headers',
label: 'Headers',
icon: 'ic:outline-list',
count: requestHeaders.value.filter(h => h.active && h.key).length
},
{
id: 'auth',
label: 'Authorization',
icon: 'ic:outline-security',
count: requestAuth.value.type !== 'none' ? 1 : 0
},
{
id: 'body',
label: 'Body',
icon: 'ic:outline-description',
count: getBodyContentCount()
}
])
// Get body content count for badge
const getBodyContentCount = () => {
if (requestBody.value.type === 'none') return 0
if (requestBody.value.type === 'raw' && requestBody.value.raw) return 1
if (requestBody.value.type === 'form-data') {
return requestBody.value.formData.filter(item => item.active && item.key).length
}
if (requestBody.value.type === 'x-www-form-urlencoded') {
return requestBody.value.urlEncoded.filter(item => item.active && item.key).length
}
return 0
}
// Computed properties for variable detection
const urlVariables = computed(() => {
return findVariables(requestUrl.value)
})
// Method to format variable name with curly braces
const formatVariableName = (name) => {
return `{{${name}}}`
}
const handleSendRequest = async () => {
if (!requestUrl.value) {
showNotification('Please enter a URL', 'error')
return
}
const requestData = {
url: requestUrl.value,
method: httpMethod.value,
headers: requestHeaders.value,
params: requestParams.value,
auth: requestAuth.value,
body: requestBody.value
}
// Process variables before sending
const processedRequest = processRequest(requestData)
await sendRequestUtil(processedRequest, {
onStart: () => {
isLoading.value = true
},
onSuccess: (responseData) => {
response.value = responseData
// Add timestamp to response
response.value.timestamp = new Date().toISOString()
// Add to history
requestHistory.value.unshift({
id: Date.now(),
timestamp: new Date().toISOString(),
name: requestName.value || 'Untitled Request',
method: httpMethod.value,
url: requestUrl.value,
status: responseData.status
})
showNotification('Request completed successfully', 'success')
},
onError: (message, responseData) => {
if (responseData) {
response.value = responseData
response.value.timestamp = new Date().toISOString()
}
showNotification(`Request failed: ${message}`, 'error')
},
onComplete: () => {
isLoading.value = false
}
})
}
</script>