(ctx context.Context, data *TemplateData)
| 335 | } |
| 336 | |
| 337 | func previewTemplate(ctx context.Context, data *TemplateData) error { |
| 338 | ctx, cancel := context.WithCancel(ctx) |
| 339 | defer cancel() |
| 340 | |
| 341 | listener, err := net.Listen("tcp", "127.0.0.1:0") |
| 342 | if err != nil { |
| 343 | return err |
| 344 | } |
| 345 | defer func() { |
| 346 | _ = listener.Close() |
| 347 | }() |
| 348 | |
| 349 | changesChan, err := broadcastTemplateChanges(ctx, data.Filename) |
| 350 | if err != nil { |
| 351 | return err |
| 352 | } |
| 353 | |
| 354 | requestTimeout := 10 * time.Minute |
| 355 | server := &http.Server{ |
| 356 | Handler: buildRoutes(requestTimeout, data, changesChan), |
| 357 | ReadTimeout: requestTimeout + time.Minute, |
| 358 | WriteTimeout: requestTimeout + time.Minute, |
| 359 | } |
| 360 | defer func() { |
| 361 | _ = server.Close() |
| 362 | }() |
| 363 | |
| 364 | go func() { |
| 365 | if err = server.Serve(listener); err != http.ErrServerClosed { |
| 366 | cancel() |
| 367 | } |
| 368 | }() |
| 369 | |
| 370 | storybookURL := &url.URL{ |
| 371 | Scheme: "http", |
| 372 | Host: listener.Addr().String(), |
| 373 | Path: "/data/branding/storybook/", |
| 374 | RawQuery: (url.Values{"path": []string{"/story/universal-login--prompts"}}).Encode(), |
| 375 | } |
| 376 | |
| 377 | if err := browser.OpenURL(storybookURL.String()); err != nil { |
| 378 | return err |
| 379 | } |
| 380 | |
| 381 | // Wait until the file is closed or input is cancelled. |
| 382 | <-ctx.Done() |
| 383 | return nil |
| 384 | } |
| 385 | |
| 386 | func buildRoutes( |
| 387 | requestTimeout time.Duration, |
no test coverage detected