Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 16 additions & 0 deletions docs/errors/OXDT0007.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
outline: deep
---
# OXDT0007: Failed to Run Oxfmt

## Message
> Failed to run Oxfmt: `{reason}`

## Cause
Oxfmt could not be started for the current workspace.

## Fix
Install Oxfmt, check its configuration, and run format again.

## Source
- [`packages/oxc/src/node/rpc/functions/oxfmt-run.ts`](https://github.com/vitejs/devtools/blob/main/packages/oxc/src/node/rpc/functions/oxfmt-run.ts) — reports execution failures.
19 changes: 19 additions & 0 deletions docs/errors/OXDT0008.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
outline: deep
---
# OXDT0008: Failed to Delete Format Result

## Message
> Failed to delete format result "`{resultId}`": `{reason}`

## Cause
The result ID is not numeric, the result no longer exists, or the project directory does not allow deletion.

## Example
Deleting a format result that another process has already removed.

## Fix
Refresh the format result list, use a numeric ID from the list, and ensure the project directory is writable.

## Source
- [`packages/oxc/src/node/rpc/functions/oxfmt-delete-result.ts`](https://github.com/vitejs/devtools/blob/main/packages/oxc/src/node/rpc/functions/oxfmt-delete-result.ts) — Validates the result ID and deletes its log directory.
2 changes: 2 additions & 0 deletions docs/errors/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,5 @@ Emitted by `@vitejs/devtools-oxc`.
| [OXDT0004](./OXDT0004) | error | Oxlint Config Inspection Failed |
| [OXDT0005](./OXDT0005) | error | Oxlint Setup Failed |
| [OXDT0006](./OXDT0006) | error | Oxfmt Setup Failed |
| [OXDT0007](./OXDT0007) | error | Failed to Run Oxfmt |
| [OXDT0008](./OXDT0008) | error | Failed to Delete Format Result |
129 changes: 129 additions & 0 deletions packages/oxc/src/app/components/RunOxfmtDialog.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<script setup lang="ts">
import ActionButton from '@vitejs/devtools-ui/components/Action/ActionButton.vue'
import FormCheckbox from '@vitejs/devtools-ui/components/Form/FormCheckbox.vue'
import OverlayModal from '@vitejs/devtools-ui/components/Overlay/OverlayModal.vue'
import VisualLoading from '@vitejs/devtools-ui/components/Visual/VisualLoading.vue'
import { ref, watch } from 'vue'
import { useRpc } from '#imports'

const open = defineModel<boolean>('open', { default: false })
const emit = defineEmits<{ complete: [write: boolean] }>()
const rpc = useRpc()

type Stage = 'confirm' | 'running' | 'success' | 'error'
const stage = ref<Stage>('confirm')
const write = ref(false)
const commandLine = ref('')
const gitDirty = ref(false)
const errorMessage = ref('')
let previewRequest = 0

async function loadPreview() {
const request = ++previewRequest
try {
const preview = await rpc.value.call('devtools-oxc:oxfmt-format-preview', {
write: write.value,
})
if (request !== previewRequest) return
commandLine.value = preview.command
gitDirty.value = preview.gitDirty
} catch (error) {
if (request !== previewRequest) return
errorMessage.value = error instanceof Error ? error.message : String(error)
}
}

watch(open, isOpen => {
if (!isOpen) return
stage.value = 'confirm'
write.value = false
commandLine.value = ''
gitDirty.value = false
errorMessage.value = ''
loadPreview()
})

watch(write, () => {
if (open.value && stage.value === 'confirm') loadPreview()
})

async function confirmRun() {
stage.value = 'running'
errorMessage.value = ''
try {
const { exitCode } = await rpc.value.call('devtools-oxc:run-format', { write: write.value })
emit('complete', write.value)
if (!open.value) return
if (!write.value) {
open.value = false
return
}
stage.value = exitCode === 0 ? 'success' : 'error'
if (exitCode !== 0) errorMessage.value = `Oxfmt exited with code ${exitCode}.`
} catch (error) {
if (!open.value) return
stage.value = 'error'
errorMessage.value = error instanceof Error ? error.message : String(error)
}
}
</script>

<template>
<OverlayModal v-model:open="open">
<template #title> Run Oxfmt with devtools </template>

<div class="flex flex-col gap-4 w-140 max-w-full min-h-64">
<template v-if="stage === 'confirm'">
<p class="m0 op70 text-sm">
{{
write
? 'Format and write files in place.'
: 'Check if files are formatted, and show statistics.'
}}
</p>
<pre
class="m0 p3 rounded-lg border border-base bg-code font-mono text-sm of-auto text-left"
><code>{{ commandLine || 'Loading…' }}</code></pre>
<p v-if="gitDirty" class="m0 text-amber text-sm flex gap-2 items-start">
<span class="i-ph-warning-duotone mt-0.5 shrink-0" />
<span>The Git working tree is not clean. Formatting may modify project files.</span>
</p>
<p v-if="errorMessage" class="m0 text-red text-sm">{{ errorMessage }}</p>
<div class="flex-auto" />
<div class="flex items-center justify-between gap-2">
<FormCheckbox v-model="write" label="Write changes" />
<div class="flex gap-2">
<ActionButton @click="open = false"> Cancel </ActionButton>
<ActionButton variant="primary" icon="i-ph-play-duotone" @click="confirmRun">
Run Format
</ActionButton>
</div>
</div>
</template>

<template v-else-if="stage === 'running'">
<VisualLoading class="flex-auto" text="Formatting…" />
<div class="flex justify-end">
<ActionButton @click="open = false"> Dismiss </ActionButton>
</div>
</template>

<template v-else>
<div
:class="stage === 'success' ? 'text-green' : 'text-red'"
class="flex gap-2 items-center"
>
<span
:class="stage === 'success' ? 'i-ph-check-circle-duotone' : 'i-ph-x-circle-duotone'"
/>
{{ stage === 'success' ? 'Formatting finished successfully.' : 'Formatting failed.' }}
</div>
<p v-if="errorMessage" class="m0 op70 text-sm">{{ errorMessage }}</p>
<div class="flex-auto" />
<div class="flex justify-end">
<ActionButton variant="primary" @click="open = false"> Close </ActionButton>
</div>
</template>
</div>
</OverlayModal>
</template>
10 changes: 10 additions & 0 deletions packages/oxc/src/app/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ const tools = computed(() => {
},
]
const oxfmtViews: ToolView[] = [
...(overview.value.oxfmt.installed
? [
{
title: 'Format Inspector',
description: 'Run and inspect formatting',
icon: 'i-ph-magnifying-glass-duotone',
to: '/oxfmt/format',
},
]
: []),
{
title: 'Documents',
description: 'Guides and references',
Expand Down
18 changes: 18 additions & 0 deletions packages/oxc/src/app/pages/oxfmt.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
<script setup lang="ts">
import PanelSideNav from '@vitejs/devtools-ui/components/Panel/PanelSideNav.vue'
import { useSideNav } from '@vitejs/devtools-ui/composables/nav'
import { useAsyncState } from '@vueuse/core'
import { createOverview } from '../utils/overview'
import { useRpc } from '#imports'

const rpc = useRpc()
const { state: overview } = useAsyncState(
() => rpc.value.call('devtools-oxc:overview'),
createOverview(),
)

useSideNav(() => [
{
Expand All @@ -13,6 +22,15 @@ useSideNav(() => [
// icon: 'i-ph-sliders-duotone',
// to: '/oxfmt/config',
// },
...(overview.value.oxfmt.installed
? [
{
title: 'Format Inspector',
icon: 'i-ph-magnifying-glass-duotone',
to: '/oxfmt/format',
},
]
: []),
{
title: 'Documents',
icon: 'i-ph-book-open-duotone',
Expand Down
Loading
Loading