Claude/resolve merge conflicts z e sy o#7
Merged
Conversation
Already implemented in AppSidebar.vue — dropdown button, account list popover, chevron, click-outside dismiss, active account checkmark. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
- vite.config.ts: explicitly set assetsDir + rollupOptions output paths so all JS/CSS/fonts/images land in dist/assets/ with content hashes regardless of future Vite defaults changing - deploy-website.ts: add explicit favicon.svg rule (1-day cache on main) since it has no content hash and shouldn't get immutable treatment; assets/* regex already correctly maps to immutable on main CloudFront: /assets/* needs a dedicated behavior in the backend infra (rhosys/ses-email-adapter deploy/) pointing to the same S3 origin with a 1-year TTL cache policy. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
- SupportPanel.vue: slide-over with three tabs (Knowledge base, Contact us, Status); searchable 8-article local knowledge base; contact form with category/subject/description that opens a pre-filled mailto: link with auto-attached account ID, user ID, route, browser, and resource ID - useSupportPanel.ts: module-level singleton ref shared between sidebar and mobile header so both buttons control the same panel - AppSidebar.vue: '?' button above profile link, hidden on mobile - AppLayout.vue: '?' button in mobile header (sm:hidden on desktop), renders <SupportPanel> at root so it overlays the full viewport https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
getUserIdentity() is synchronous and returns JWT claims directly (sub field = user ID). No need for the async getUserProfile() + linkedIdentities[0].connection.userId indirection. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
aws-architect only sets aws.config.region from apiOptions.regions when
the global region is unset. When configure-aws-credentials had eu-west-1
as its default, aws.config.region was already set and our
regions: ['eu-central-1'] was silently ignored, causing NoSuchBucket.
Calling AWS.config.update({ region }) before instantiation ensures the
correct region is always used regardless of the env default.
https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Replaces the explicit AWS.config.update('eu-central-1') with the same
pattern the backend uses: read AWS_REGION from the environment and pass
as regions: [region]. configure-aws-credentials sets AWS_REGION in CI;
'eu-central-1' is the fallback for local runs without env configured.
https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
…on bar - QuarantineFilters: sender input grows full-width on mobile (w-full sm:w-48), wrapper switches to flex-1 on narrow screens, date inputs and clear button get min touch height (py-1.5, min-h-[36px]) - RuleEditorView: test-rule grid uses sm:grid-cols-2 so inputs stack on mobile - BulkActionBar: label form wraps (flex-wrap) and input expands full-width on mobile (w-full sm:w-auto) - viewports.ts: add 390×844 mobile viewport (iPhone 14) - playwright.config.ts: add mobile project using iPhone 14 device preset - layout.responsive.test.ts: add no-overflow and element-fit assertions for quarantine, rules, settings, and inbox routes https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Touch targets: bump all action buttons and form inputs from py-1 to py-1.5 (QuarantineRow allow/reject/rule links, BulkActionBar archive/label, StatusTabs tabs, RuleEditorView condition selects/inputs/add-action, SettingsView recheck and role select) Layout: LabelsView view-form grid stacks to single column on mobile (grid-cols-2 → sm:grid-cols-2); OnboardingView domain and sender forms get flex-wrap so the submit button drops below the input on very narrow screens; ProfileView passkey form gets flex-wrap Overflow: AuditLogView event type and resource ID get min-w-0 + truncate so long monospace IDs don't blow out the row; SignalCard plain-text body gets break-words so long unspaced lines wrap instead of overflowing the panel https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Inbox (/): ?tab=archived|all reflects the active status tab; default (active) uses clean URL. Tab is restored on mount so /?tab=archived is a valid bookmark. Quarantine (/quarantine): ?sender=, ?after=, ?before= reflect active filters; the filter watch now also calls router.replace so every filter change updates the URL atomically with the refetch. Filters are hydrated from URL on mount. Settings (/settings): ?tab=emails|domains|forwarding|team|notifications reflects the active tab (default account uses clean URL). /settings/notifications now redirects to /settings?tab=notifications instead of rendering a duplicate route. Labels (/labels): ?tab=views reflects the active tab; default labels uses clean URL. Audit log (/audit-log): ?cursor= is updated after every page load (initial or Load-more). Navigating to /audit-log?cursor=X starts the log from that cursor position, so any page in the log is deep-linkable. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
…o check LabelsView tab buttons had multi-statement @click expressions that Prettier reformatted to newline-separated form — valid JS but rejected by Vue's template compiler. Extracted into a selectTab() method so the handler is a single call. Added vite build to the check script so template parse errors are caught locally (vue-tsc --noEmit doesn't exercise the Vite plugin chain, so errors like this slipped through to CI). https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
…, changelog, titles
Bugs fixed:
- SettingsView saveNotifications() was sending {} to the API; now sends the
full notifications.email object (enabled, address, frequency)
- updateAccount() body type extended to include NotificationSettings
- BillingView "Open billing portal" button wired to VITE_BILLING_PORTAL_URL
env var (shows configuration hint when unset); loads real account data
instead of hardcoded "Pro" plan text
Navigation:
- /changelog route added with ChangelogView listing v0.1.0 changes;
SupportPanel router-link now resolves correctly
- Catch-all 404 route added; NotFoundView with back-to-inbox button
Cleanup:
- Deleted src/stores/onboarding.ts (defined but never imported anywhere;
OnboardingView manages its own local state)
UX:
- router.afterEach sets document.title per route so browser tabs and
history entries are distinguishable
https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
… TODOs - CI was configuring AWS credentials for eu-central-1 but all infra (S3 bucket, CloudFront) lives in eu-west-1 — deploy-website.ts inherits the credentials region, so uploads landed against the wrong endpoint and got NoSuchBucket. Pass aws_region: eu-west-1 to the setup action in both the build and cleanup jobs. - Replace the catch-all 404 route with a redirect to / so unknown paths always land on the inbox rather than a dead-end page. - Add a consolidated "Backend routes the frontend calls" section to TODO.md listing every unimplemented /accounts/* endpoint so they can be ported to rhosys/ses-email-adapter. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
The state bucket happens to be named with eu-west-1 but the deployed S3 site bucket is in the default region (eu-central-1). The prior commit incorrectly changed both jobs to eu-west-1. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Outputs the bucket name and CF distribution ID read from OpenTofu state, the active AWS region env vars, the caller identity (to confirm which account/role is assumed), and a head-bucket check so we can see whether the bucket exists and is accessible from CI. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
… and BillingView redesign - src/types/server.ts: add BillingPlan, BillingStatus, BillingInfo types - src/lib/api.ts: add createAccount, getBilling, createCheckoutSession, createBillingPortalSession; import BillingInfo - src/stores/account.ts: add fetched flag, createAccount action (stores new account, updates session/local storage) - src/router/index.ts: mark onboarding requiresAuth, add account-check guard that redirects to onboarding when no account exists - src/views/OnboardingView.vue: rewrite as 6-step wizard (Account, Domain, Test email, Sender, Filter mode, Done); skips account step for returning users - src/views/BillingView.vue: full redesign with plan tier grid (Free/Starter/Pro), Stripe checkout redirect, billing portal session, success banner - TODO.md: clarify POST /accounts is needed for self-service onboarding; add POST /billing/portal-session to backend route list https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Prettier now runs as a separate non-blocking step (continue-on-error: true) so formatting issues surface as warnings without failing the build. Removed it from the blocking `check` script — the existing `format:check` script remains for local use. Debug step additions: - `tofu output -json` dumps ALL available OpenTofu outputs so we can see exactly what keys exist and what values they hold - `aws s3api list-buckets` lists the first 20 buckets in the account so we can cross-check the expected bucket name against what actually exists https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
The Terraform state stores the bucket name with eu-west-1 baked in but the actual bucket lives in eu-central-1. Pipe the tofu output through sed to correct the region before writing to GITHUB_ENV. Applied to both the build and cleanup jobs. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Preview deployedURL: https://email.rhosys.cloud/pr/claude-resolve-merge-conflicts-zesyo/
|
Removes VITE_STRIPE_PRICE_STARTER / VITE_STRIPE_PRICE_PRO env vars from BillingView — price IDs are now hardcoded TODO placeholders to be replaced with real Stripe price IDs once the account is set up. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
LoginView was calling authenticate() unconditionally on every mount, including when Authress redirected back after a successful login. Since no redirectUrl was set, Authress returned to /login, remounting the view and restarting the flow. Fix: call userSessionExists() first, which processes any OAuth callback params in the URL. If a session is established, redirect to /. Only call authenticate() when there is genuinely no session, and set an explicit redirectUrl pointing to the app root so Authress never returns to /login. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Every empty state now has a bold primary headline and a sentence explaining what the section does and how to get started: - Inbox (active/archived/all): explain DNS setup requirement / archive purpose - Quarantine: explain filter mode and the approve/block workflow - Search: suggest alternative search terms and fields - Settings → Aliases: explain per-address filter modes - Settings → Domains: explain DNS verification requirement - Settings → Forwarding: explain how forwarding addresses tie into rules - Reply composer: clarify verified domain requirement with a settings link https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Across inbox, quarantine, search, settings (aliases, domains, forwarding, team),
rules, labels, and views — replaced flat descriptive text with copy that frames
the value of taking the next step: loss framing, friction-removal cues ("usually
within minutes", "one click away"), and clear forward motion.
https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Router guard now passes the original path as ?redirect= when bouncing unauthenticated users to /login. LoginView uses it as the Authress OAuth callback URL so the user lands at the correct page after authenticating, rather than always hitting the inbox root. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Previously passed the destination path directly as the OAuth callback URL, which would fail unless every deep-link is a registered redirect URI in Authress. Now uses window.location.href so Authress returns to /login?redirect=<destination>, and LoginView handles the final navigation. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
- Store keeps quarantine_visible and quarantine_hidden in separate arrays
instead of merging them; each bucket is sorted by receivedAt desc
- fetchMore exhausts all visible pages before loading hidden pages,
preserving the visible-first ordering across pagination
- QuarantineView renders two labelled sections ("Needs review" /
"Silently held") with a single Load more button at the bottom
- Updated quarantine store tests to cover the new bucket API and
the visible-before-hidden fetchMore ordering
https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
visibleItems/hiddenItems renamed to quarantineVisible/quarantineHidden, mirroring the quarantine_visible/quarantine_hidden status values from the API. Also fixes RuleEditorView which referenced the removed .items property. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
- EmailTemplate type in server.ts - API methods: list, create, update (PUT), delete - useTemplatesStore (Pinia) with loading/error state - TemplatesView at /templates: list, inline editor with edit/preview tabs, Handlebars variable chip palette, live preview via marked - Templates sidebar link between Rules and Labels - Rule editor: auto_reply/auto_draft actions now use a template dropdown instead of a raw ID input, with a "Manage" link to /templates - Updated RuleEditorView test to mock listTemplates and fix stale quarantine store reference (items → quarantineVisible/quarantineHidden) https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Expands the email templates backend section with the full EmailTemplate resource shape, supported interpolation variables, exact endpoint signatures (request/response bodies, status codes), and the rule integration behaviour for auto_reply/auto_draft. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Templates now support named JS functions alongside static sender variables.
Each function receives (signal, arc) and returns a string; outputs are
referenced in the body/subject as {{fn.name}}.
- TemplateFunction type added to server.ts
- EmailTemplate.functions field added
- API and store bodies updated to include functions
- Template editor: function list with name + code textarea per entry,
add/remove controls, default starter expression
- Preview runs functions in an inline Worker (sandboxed from main thread),
shows resolved fn.* outputs alongside the rendered HTML
- Static variable chips replaced with inline label showing available tokens
- TODO updated with full backend contract: resource shape, security
requirements (sandboxed VM), and render pipeline for auto_reply/auto_draft
https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
- useToast composable: module-level singleton with showUndo (action done, undo reverses) and deferAction (action pending, timeout commits) - ToastStack component: fixed bottom-right, SVG countdown ring draining in real time, prominent mauve Undo/Cancel button, springs in on entry - Dynamic send window via undoWindowMs(): <50 words → 10s, 50–199 → 1min, 200–499 → 3min, 500+ → 5min - DraftSignalCard: send is now deferred — clicking Send queues the email and shows a countdown toast; Cancel send (in toast or in card) aborts the send - ArcDetailView: archive shows an 8s undo toast; undo PATCHes the arc back to active and reloads the thread - Mark toast/undo task done in TODO.md https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Send is now called immediately on click; the toast countdown gives the user a window to cancel. Cancelling PATCHes the signal status back to 'draft' — if the backend reports the email already delivered, the card emits 'sent' and surfaces an error message instead. Adds api.patchSignal (PATCH /accounts/:id/signals/:id) alongside the existing send and delete helpers. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Replaces all plain "Loading…" text across InboxView, ArcDetailView, QuarantineView, RulesView, TemplatesView, LabelsView (×2), AuditLogView, BillingView, SettingsView (×4), and ProfileView (×2) with animate-pulse placeholder rows that match the shape of the real content. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Inbox zero: CSS fireworks overlay fires once when the active tab transitions from items to empty (never on initial load). Auto-dismisses after 3.4 s with a spring card entrance/exit transition. Feature tour: spotlight-based 5-step walkthrough (Inbox → Quarantine → Rules → Labels → Settings) using a box-shadow cutout on data-tour anchors in AppSidebar. Auto-starts after onboarding completes on first login. Permanently dismissed by PATCH onboarding.featureTourCompleted on the account. Re-triggerable via a "Start tour" button on the Profile page. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Toast window is now fixed at 30 s regardless of email length — the dynamic window was impractical for a global notification bar. After the toast expires (or is dismissed), user-sent signals show an "Undo send" footer button inside the expanded SignalCard that PATCHes the signal status back to draft. On success the thread re-fetches so the draft card reappears; on failure (already delivered) an inline error is shown. ArcDetailView now re-fetches on sent, discarded, and undo events so the thread stays in sync with backend state in all cases. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
- ArcRow: expandable tree row with lazy-loaded child SignalRows, hover-revealed Reply + Archive buttons, expand chevron - SignalRow: new compact signal row with overflow menu (View Original Email, Undo send) - SignalCard: replace bottom undo bar with overflow menu (View Original Email, Undo send) - ArcDetailView: move Archive + Reply buttons to arc header; remove standalone bottom Archive button - arcs store: add removeArc() for optimistic removal after single-arc archive - ArcRow test: add setActivePinia/createPinia in beforeEach for new store dependencies https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
…clone - InviteView: /invite?inviteId=<id> unauthenticated route; extracts inviteId, checks for OAuth error params, calls userSessionExists() then authenticate() with categorized error messages (expired / already used / not found / invalid) - Error tracking: logger.ts (relay POST to relay.rhosys.ch), buildInfo.ts, environment.ts, analytics.ts (PostHog init with session recording + masking); Vue errorHandler + unhandledrejection + router.onError + beforeunload flush all wired in main.ts; set VITE_POSTHOG_KEY + VITE_POSTHOG_HOST to enable - vite.config.ts: inject VERSION_INFO and DEPLOYMENT_INFO globals at build time - TemplatesView: Clone button opens editor pre-filled with "Copy of <name>" - posthog-js added as dependency https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Flow: after user views the test arc (or 20s passes), a floating card slides up in the bottom-right showing an incoming-email-style message. - Step 1: asks to enable browser notifications; if granted fires a demo notification so the user immediately sees how it works - Step 2: offers to start the feature tour right now; clicking Start tour dismisses the coach and launches the existing walkthrough InboxView arms the 20s timer on unmount (user leaving for arc-detail) and fires the coach immediately on remount (user returning to inbox). The timer in useOnboardingCoach is module-level so it survives the InboxView unmount/remount cycle. AppLayout now gates tour auto-start behind notificationCoachCompleted so the coach always runs first for fresh users; returning users who already completed the coach but skipped the tour still get it on next load. - useOnboardingCoach.ts: arm/trigger/dismiss singleton - OnboardingCoach.vue: Teleport'd floating card with 2-step flow - OnboardingState: add notificationCoachCompleted flag https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
armed → countdownRunning arm() → startArcViewCountdown() trigger() → showCoachNow() dismissCoach() → hideCoach() coachActive → coachVisible https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
- New `src/stores/shortcuts.ts`: flat binding list persisted to localStorage under `ses-ui.shortcuts`. Five presets: Default (Gmail-style), Gmail, Superhuman, Spark (Readdle), and Fastmail — capturing the major web email client conventions. `loadPreset()` populates the full binding list; individual `setBinding()` overrides. - New `src/composables/useKeyboardShortcuts.ts`: module-level singleton registers one `document.keydown` capture-phase listener. Handles two-key g→X sequences (500 ms window), guards against firing inside inputs, exposes `onAction`/`offAction` for per-view handler registration, `setCapturing` for key-record mode, `setBlocked` to suppress shortcuts while the help overlay is open. - New `src/components/ShortcutHelpOverlay.vue`: `?`-triggered modal (Teleport'd, v-model:open). Preset chips let users load any scheme with one click. Grouped shortcut table with per-row Edit / clear buttons. Edit mode captures the next keypress, shows conflict warnings with "Save anyway" option that nullifies conflicting bindings. Footer has "Reset all to defaults" button. - `InboxView`: j/k focused-arc navigation with scroll-into-view, Enter/o opens, e archives, x toggles selection. `focusedArcId` passed to ArcList. - `ArcList`: new optional `focusedArcId` prop forwarded to ArcRow. - `ArcRow`: new optional `focused` prop adds `ring-1 ring-inset ring-ctp-mauve` highlight; outer div gets `data-arc-id` for querySelector scroll lookup. - `AppLayout`: calls `initShortcuts()` on mount, registers global go-to and search handlers, adds `<ShortcutHelpOverlay>`, blocks shortcuts when overlay is open. - `ProfileView`: "Keyboard shortcuts" card with Customize button that opens the overlay. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Warns via ::warning:: annotations if any JS chunk exceeds 400 KB or the total JS bundle exceeds 1 MB. Uses continue-on-error so the build always proceeds regardless. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
When a new arc or signal event arrives over the SharedWorker WebSocket, fire a Notification() if permission is granted and the arc urgency clears the threshold derived from the user's email digest frequency preference: - instant (or unset): critical, high, normal - hourly: critical, high only - daily: critical only - low / silent: never notify Notification title reflects urgency (🚨 Critical /⚠️ High / New email). The `tag` field deduplicates OS-level notifications for the same arc. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Browser notifications fire purely on arc urgency: critical / high / normal → notify, low / silent → skip. The email digest frequency is unrelated to browser notification behaviour. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Adds src/types/realtime.ts with a discriminated union of all server event shapes. Each event type carries just enough for useful notifications and store invalidation — IDs, urgency, from, subject — without the full entity. useRealtime.ts now narrows on event.type via a switch, so fireNotification only handles signal:created and arc:created (the only events with urgency and sender info), and the switch exhausts all known event types cleanly. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
src/types/realtime.ts: replace 9 CRUD events with just two — signal:created (arcId, signalId, urgency, from, subject) arc:updated (arcId only — client re-fetches) useRealtime.ts: remove unused quarantine/rules store imports, tighten handleEvent switch, fireNotification now takes SignalCreatedEvent directly with no type narrowing needed. TODO.md: add backend WebSocket event requirements so the server knows exactly what payload each event must carry. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
…ist reload arcs store: add refreshArc(arcId) — fetches one arc via api.getArc() and upserts it into the items list (updates in place if present, prepends if new). useRealtime: on signal:created or arc:updated, call arcsStore.refreshArc() for a targeted inbox update. If the signals store currently has that arc's detail open (signalsStore.arc?.id === event.arcId), also call signalsStore.fetchAll() to pull the arc + its recent signals together. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Router guard was redirecting all non-onboarding routes back to /onboarding when onboarding.completed was false — including profile and billing. Exempt those two routes so authenticated users can always reach them. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
- UserAvatar hover popup now has a Sign out button alongside View full profile - .env.production sets VITE_POSTHOG_KEY and VITE_POSTHOG_HOST for prod builds - analytics.ts: derive ui_host from host — proxy ingestion URLs keep the PostHog dashboard UI pointing at eu.posthog.com https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Remove hardcoded VITE_POSTHOG_HOST from .env.production; pass it via the Build step env using secrets.POSTHOG_URL so the value never lives in the repo. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
- Browser push notifications: mark [x] — frontend complete, blocked on backend WS - Remove: CSV export, import/export rules/templates/labels, changelog badge - Add backend TODOs: Webhooks UI and API keys management - Webhooks/API keys frontend items remain open pending backend https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
- tests/e2e/a11y.test.ts: audit 6 main routes with wcag2a + wcag2aa tags; stubs auth + API so tests run without a live backend; failure message prints violation ID, description, and target selectors - TODO: note to extend to full route list + wcag21 tags once views are stable - TODO: JMAP backend spec (RFC 8620/8621) with frontend adapter flag https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
Bundle-size CI hardening, axe-core route expansion, test coverage backfill, modular component system, and AI rule action are all deferred until after the app ships. Added a clear V2 section with that rationale. https://claude.ai/code/session_017L42eZnAdHChzFwEjKR7Rb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.