or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

helpers.mdindex.mdmutations.mdplugin-setup.mdqueries.mdquery-client.mdstatus-utilities.md

status-utilities.mddocs/

0

# Status & Utilities

1

2

Utility composables for tracking query and mutation status across the application, providing reactive counters and state monitoring.

3

4

## Capabilities

5

6

### useIsFetching

7

8

Composable to track the number of queries currently fetching data.

9

10

```typescript { .api }

11

/**

12

* Track the number of queries currently fetching

13

* @param filters - Optional filters to match specific queries

14

* @param queryClient - Optional query client instance

15

* @returns Reactive ref containing the count of fetching queries

16

*/

17

function useIsFetching(

18

filters?: QueryFilters,

19

queryClient?: QueryClient

20

): Ref<number>;

21

22

interface QueryFilters {

23

exact?: boolean;

24

fetchStatus?: FetchStatus;

25

predicate?: (query: Query) => boolean;

26

queryKey?: QueryKey;

27

stale?: boolean;

28

status?: QueryStatus;

29

type?: QueryTypeFilter;

30

}

31

32

type FetchStatus = 'fetching' | 'paused' | 'idle';

33

type QueryStatus = 'pending' | 'error' | 'success';

34

type QueryTypeFilter = 'all' | 'active' | 'inactive';

35

```

36

37

**Usage Examples:**

38

39

```typescript

40

import { useIsFetching } from '@tanstack/vue-query';

41

42

export default {

43

setup() {

44

// Track all fetching queries

45

const fetchingCount = useIsFetching();

46

47

// Track specific query families

48

const userFetchingCount = useIsFetching({ queryKey: ['user'] });

49

const postsFetchingCount = useIsFetching({ queryKey: ['posts'] });

50

51

// Track queries with specific status

52

const staleFetchingCount = useIsFetching({ stale: true });

53

54

// Show global loading indicator

55

const isGlobalLoading = computed(() => fetchingCount.value > 0);

56

57

// Show section-specific loading

58

const isUserSectionLoading = computed(() => userFetchingCount.value > 0);

59

60

return {

61

fetchingCount,

62

isGlobalLoading,

63

isUserSectionLoading

64

};

65

}

66

};

67

68

// Custom predicate filtering

69

const apiCallsCount = useIsFetching({

70

predicate: (query) => query.queryKey[0] === 'api'

71

});

72

73

// Multiple filters combined

74

const criticalFetchingCount = useIsFetching({

75

queryKey: ['critical'],

76

fetchStatus: 'fetching',

77

stale: false

78

});

79

```

80

81

### useIsMutating

82

83

Composable to track the number of mutations currently pending.

84

85

```typescript { .api }

86

/**

87

* Track the number of mutations currently pending

88

* @param filters - Optional filters to match specific mutations

89

* @param queryClient - Optional query client instance

90

* @returns Reactive ref containing the count of pending mutations

91

*/

92

function useIsMutating(

93

filters?: MutationFilters,

94

queryClient?: QueryClient

95

): Ref<number>;

96

97

interface MutationFilters {

98

exact?: boolean;

99

fetching?: boolean;

100

mutationKey?: MutationKey;

101

predicate?: (mutation: Mutation) => boolean;

102

status?: MutationStatus;

103

}

104

105

type MutationStatus = 'idle' | 'pending' | 'success' | 'error';

106

```

107

108

**Usage Examples:**

109

110

```typescript

111

import { useIsMutating } from '@tanstack/vue-query';

112

113

export default {

114

setup() {

115

// Track all pending mutations

116

const mutatingCount = useIsMutating();

117

118

// Track specific mutation types

119

const savingCount = useIsMutating({ mutationKey: ['save'] });

120

const deletingCount = useIsMutating({ mutationKey: ['delete'] });

121

122

// Track mutations with specific status

123

const pendingMutations = useIsMutating({ status: 'pending' });

124

const erroredMutations = useIsMutating({ status: 'error' });

125

126

// Show global saving indicator

127

const isSaving = computed(() => mutatingCount.value > 0);

128

129

// Show action-specific indicators

130

const isDeleting = computed(() => deletingCount.value > 0);

131

132

// Disable UI during mutations

133

const isFormDisabled = computed(() => savingCount.value > 0);

134

135

return {

136

mutatingCount,

137

isSaving,

138

isDeleting,

139

isFormDisabled

140

};

141

}

142

};

143

144

// Custom predicate filtering

145

const uploadCount = useIsMutating({

146

predicate: (mutation) =>

147

mutation.options.mutationKey?.[0] === 'upload'

148

});

149

150

// Filter by mutation function

151

const postMutationsCount = useIsMutating({

152

predicate: (mutation) =>

153

mutation.options.mutationFn?.name === 'createPost'

154

});

155

```

156

157

### useMutationState

158

159

Composable to access and monitor mutation state across the application.

160

161

```typescript { .api }

162

/**

163

* Access mutation state across the application

164

* @param options - Configuration for selecting and filtering mutations

165

* @param queryClient - Optional query client instance

166

* @returns Readonly ref containing array of selected mutation results

167

*/

168

function useMutationState<TResult = MutationState>(

169

options?: MutationStateOptions<TResult>,

170

queryClient?: QueryClient

171

): Readonly<Ref<Array<TResult>>>;

172

173

interface MutationStateOptions<TResult = MutationState> {

174

filters?: MutationFilters;

175

select?: (mutation: Mutation) => TResult;

176

}

177

178

interface MutationState<TData = unknown, TError = DefaultError, TVariables = unknown, TContext = unknown> {

179

context: TContext | undefined;

180

data: TData | undefined;

181

error: TError | null;

182

failureCount: number;

183

failureReason: TError | null;

184

isPaused: boolean;

185

status: MutationStatus;

186

submittedAt: number;

187

variables: TVariables | undefined;

188

}

189

```

190

191

**Usage Examples:**

192

193

```typescript

194

import { useMutationState } from '@tanstack/vue-query';

195

196

export default {

197

setup() {

198

// Get all mutation states

199

const allMutations = useMutationState();

200

201

// Get mutations with specific filters

202

const saveMutations = useMutationState({

203

filters: { mutationKey: ['save'] }

204

});

205

206

// Get pending mutations only

207

const pendingMutations = useMutationState({

208

filters: { status: 'pending' }

209

});

210

211

// Select specific data from mutations

212

const uploadProgress = useMutationState({

213

filters: { mutationKey: ['upload'] },

214

select: (mutation) => ({

215

id: mutation.mutationId,

216

progress: mutation.context?.progress || 0,

217

filename: mutation.variables?.filename,

218

status: mutation.status

219

})

220

});

221

222

// Get error states for display

223

const mutationErrors = useMutationState({

224

filters: { status: 'error' },

225

select: (mutation) => ({

226

error: mutation.error,

227

variables: mutation.variables,

228

timestamp: mutation.submittedAt

229

})

230

});

231

232

// Recent successful mutations

233

const recentSuccesses = useMutationState({

234

filters: { status: 'success' },

235

select: (mutation) => ({

236

data: mutation.data,

237

completedAt: mutation.submittedAt,

238

variables: mutation.variables

239

})

240

});

241

242

// Compute derived state

243

const hasErrors = computed(() => mutationErrors.value.length > 0);

244

const overallProgress = computed(() => {

245

const uploads = uploadProgress.value;

246

if (uploads.length === 0) return 0;

247

const total = uploads.reduce((sum, upload) => sum + upload.progress, 0);

248

return total / uploads.length;

249

});

250

251

return {

252

allMutations,

253

uploadProgress,

254

mutationErrors,

255

hasErrors,

256

overallProgress

257

};

258

}

259

};

260

261

// Real-time activity monitoring

262

const activityFeed = useMutationState({

263

select: (mutation) => ({

264

id: mutation.mutationId,

265

type: mutation.options.mutationKey?.[0],

266

status: mutation.status,

267

timestamp: mutation.submittedAt,

268

error: mutation.error?.message,

269

data: mutation.data

270

})

271

});

272

273

// Sort by most recent

274

const sortedActivity = computed(() =>

275

[...activityFeed.value].sort((a, b) => b.timestamp - a.timestamp)

276

);

277

278

// Filter by time range

279

const recentActivity = computed(() => {

280

const hourAgo = Date.now() - 60 * 60 * 1000;

281

return activityFeed.value.filter(item => item.timestamp > hourAgo);

282

});

283

284

// Form submission tracking

285

const formSubmissions = useMutationState({

286

filters: {

287

predicate: (mutation) =>

288

mutation.options.mutationKey?.[0] === 'form' &&

289

mutation.status === 'pending'

290

},

291

select: (mutation) => ({

292

formId: mutation.variables?.formId,

293

submittedAt: mutation.submittedAt,

294

progress: mutation.context?.uploadProgress

295

})

296

});

297

```

298

299

## Status Monitoring Patterns

300

301

**Usage Examples:**

302

303

```typescript

304

// Global application status

305

export default {

306

setup() {

307

const isFetching = useIsFetching();

308

const isMutating = useIsMutating();

309

310

// Application busy state

311

const isAppBusy = computed(() =>

312

isFetching.value > 0 || isMutating.value > 0

313

);

314

315

// Critical operations status

316

const criticalFetching = useIsFetching({

317

predicate: query => query.meta?.critical === true

318

});

319

320

const criticalMutating = useIsMutating({

321

predicate: mutation => mutation.meta?.critical === true

322

});

323

324

const isCriticalBusy = computed(() =>

325

criticalFetching.value > 0 || criticalMutating.value > 0

326

);

327

328

// Show different loading states

329

const loadingState = computed(() => {

330

if (isCriticalBusy.value) return 'critical';

331

if (isAppBusy.value) return 'busy';

332

return 'idle';

333

});

334

335

return {

336

loadingState,

337

isAppBusy,

338

isCriticalBusy

339

};

340

}

341

};

342

343

// Error aggregation

344

const useErrorSummary = () => {

345

const errorMutations = useMutationState({

346

filters: { status: 'error' },

347

select: mutation => ({

348

type: mutation.options.mutationKey?.[0],

349

error: mutation.error,

350

timestamp: mutation.submittedAt

351

})

352

});

353

354

const errorSummary = computed(() => {

355

const errors = errorMutations.value;

356

const byType = errors.reduce((acc, err) => {

357

const type = err.type || 'unknown';

358

acc[type] = (acc[type] || 0) + 1;

359

return acc;

360

}, {});

361

362

return {

363

total: errors.length,

364

byType,

365

recent: errors.filter(err =>

366

Date.now() - err.timestamp < 5 * 60 * 1000 // Last 5 minutes

367

)

368

};

369

});

370

371

return { errorSummary };

372

};

373

374

// Progress tracking

375

const useUploadProgress = () => {

376

const uploads = useMutationState({

377

filters: { mutationKey: ['upload'] },

378

select: mutation => ({

379

id: mutation.mutationId,

380

filename: mutation.variables?.filename,

381

progress: mutation.context?.progress || 0,

382

status: mutation.status,

383

error: mutation.error

384

})

385

});

386

387

const overallProgress = computed(() => {

388

const activeUploads = uploads.value.filter(u => u.status === 'pending');

389

if (activeUploads.length === 0) return 100;

390

391

const totalProgress = activeUploads.reduce((sum, upload) =>

392

sum + upload.progress, 0

393

);

394

return Math.round(totalProgress / activeUploads.length);

395

});

396

397

return { uploads, overallProgress };

398

};

399

```

400

401

## Types

402

403

```typescript { .api }

404

// Filter types

405

interface QueryFilters {

406

exact?: boolean;

407

fetchStatus?: FetchStatus;

408

predicate?: (query: Query) => boolean;

409

queryKey?: QueryKey;

410

stale?: boolean;

411

status?: QueryStatus;

412

type?: QueryTypeFilter;

413

}

414

415

interface MutationFilters {

416

exact?: boolean;

417

fetching?: boolean;

418

mutationKey?: MutationKey;

419

predicate?: (mutation: Mutation) => boolean;

420

status?: MutationStatus;

421

}

422

423

// State types

424

type FetchStatus = 'fetching' | 'paused' | 'idle';

425

type QueryStatus = 'pending' | 'error' | 'success';

426

type MutationStatus = 'idle' | 'pending' | 'success' | 'error';

427

type QueryTypeFilter = 'all' | 'active' | 'inactive';

428

429

// Mutation state interface

430

interface MutationState<TData = unknown, TError = DefaultError, TVariables = unknown, TContext = unknown> {

431

context: TContext | undefined;

432

data: TData | undefined;

433

error: TError | null;

434

failureCount: number;

435

failureReason: TError | null;

436

isPaused: boolean;

437

status: MutationStatus;

438

submittedAt: number;

439

variables: TVariables | undefined;

440

}

441

442

// Options interfaces

443

interface MutationStateOptions<TResult = MutationState> {

444

filters?: MutationFilters;

445

select?: (mutation: Mutation) => TResult;

446

}

447

448

type DefaultError = Error;

449

```