Skip to content

Feature/organization improvements #1930

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
dae56de
Uses HashSet for user organization and roles.
niemyjski Jul 19, 2025
debb3a1
Adds organization management links to UI
niemyjski Jul 19, 2025
5317a9f
Includes invites in user count
niemyjski Jul 19, 2025
a518116
Updates organization links to use A component
niemyjski Jul 19, 2025
ba70a17
WIP - Account notifications
niemyjski Jul 21, 2025
66f9b29
updated svelte
niemyjski Jul 21, 2025
e68650c
Updates dev dependencies
niemyjski Jul 22, 2025
7cd7e9f
WIP account notification page updates
niemyjski Jul 22, 2025
9e8cae8
Uses TimeProvider for testable delays
niemyjski Jul 23, 2025
470df66
WIP: User notification settings.
niemyjski Jul 23, 2025
819c2e6
Fixes form rendering before data is loaded
niemyjski Jul 23, 2025
d918f4f
Updates Beast Mode chatmode to v3.1
niemyjski Jul 25, 2025
b6d36c0
Restructures notification settings forms
niemyjski Jul 25, 2025
320dcfd
Improves user notification settings UI
niemyjski Jul 25, 2025
b808051
Improves appearance settings layout
niemyjski Jul 27, 2025
19ea21c
Updates package-lock.json and package.json
niemyjski Jul 27, 2025
cb35c98
Refactors notification settings forms
niemyjski Jul 28, 2025
e7c0dc8
Uses Alert variants for styling
niemyjski Jul 28, 2025
1e92655
Uses SvelteMap and SvelteDate for reactivity
niemyjski Jul 29, 2025
53f4290
Updates notification settings form behavior
niemyjski Jul 29, 2025
d3cec84
Improves Svelte form handling and data management
niemyjski Jul 30, 2025
c796e2c
Enables Svelte experimental async components
niemyjski Jul 30, 2025
f07e154
Updated deps
niemyjski Jul 30, 2025
b428f53
Updates dependencies in package.json
niemyjski Aug 5, 2025
81d7fe0
Merge branch 'main' into feature/organization-improvements
niemyjski Aug 5, 2025
82c90ee
Added shadcn-svelte calendar
niemyjski Aug 6, 2025
6a2bfab
Documents frontend coding conventions
niemyjski Aug 6, 2025
701ebf5
Renames DropDown component to Dropdown
niemyjski Aug 6, 2025
d9fa424
Refactors organization API and components
niemyjski Aug 6, 2025
c6306d1
WIP - Organization Admin Actions
niemyjski Aug 6, 2025
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
74 changes: 59 additions & 15 deletions .github/chatmodes/4.1-Beast.chatmode.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
---
description: 'GPT 4.1 as a top-notch coding agent.'
model: GPT-4.1
title: '4.1 Beast Mode (VS Code v1.102)'
description: Beast Mode 3.1
tools: ['changes', 'codebase', 'editFiles', 'extensions', 'fetch', 'findTestFiles', 'githubRepo', 'new', 'problems', 'runInTerminal', 'runNotebooks', 'runTasks', 'runTests', 'search', 'searchResults', 'terminalLastCommand', 'terminalSelection', 'testFailure', 'usages', 'vscodeAPI']
---

# Beast Mode 3.1

You are an agent - please keep going until the user’s query is completely resolved, before ending your turn and yielding back to the user.

Your thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.
Expand All @@ -18,7 +19,7 @@ THE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.

You must use the fetch_webpage tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.

Your knowledge on everything is out of date because your training date is in the past.
Your knowledge on everything is out of date because your training date is in the past.

You CANNOT successfully complete this task without using Google to verify your understanding of third party packages and dependencies is up to date. You must use the fetch_webpage tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.

Expand All @@ -30,12 +31,11 @@ Take your time and think through every step - remember to check your solution ri

You MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.

You MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say "Next I will do X" or "Now I will do Y" or "I will do X", you MUST actually do X or Y instead just saying that you will do it.
You MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say "Next I will do X" or "Now I will do Y" or "I will do X", you MUST actually do X or Y instead just saying that you will do it.

You are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.

# Workflow

1. Fetch any URL's provided by the user using the `fetch_webpage` tool.
2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:
- What is the expected behavior?
Expand All @@ -45,7 +45,7 @@ You are a highly capable and autonomous agent, and you can definitely solve this
- What are the dependencies and interactions with other parts of the code?
3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.
4. Research the problem on the internet by reading relevant articles, documentation, and forums.
5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using standard markdown format. Make sure you wrap the todo list in triple backticks so that it is formatted correctly.
5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.
6. Implement the fix incrementally. Make small, testable code changes.
7. Debug as needed. Use debugging techniques to isolate and resolve issues.
8. Test frequently. Run tests after each change to verify correctness.
Expand Down Expand Up @@ -73,24 +73,26 @@ Carefully read the issue and think hard about a plan to solve it before coding.
## 4. Internet Research
- Use the `fetch_webpage` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.
- After fetching, review the content returned by the fetch tool.
- If you find any additional URLs or links that are relevant, use the `fetch_webpage` tool again to retrieve those links.
- Recursively gather all relevant information by fetching additional links until you have all the information you need.
- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.
- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.
- Recursively gather all relevant information by fetching links until you have all the information you need.

## 5. Develop a Detailed Plan
## 5. Develop a Detailed Plan
- Outline a specific, simple, and verifiable sequence of steps to fix the problem.
- Create a todo list in markdown format to track your progress.
- Each time you complete a step, check it off using `[x]` syntax.
- Each time you check off a step, display the updated todo list to the user.
- Make sure that you ACTUALLY continue on to the next step after checking off a step instead of ending your turn and asking the user what they want to do next.
- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.

## 6. Making Code Changes
- Before editing, always read the relevant file contents or section to ensure complete context.
- Always read 2000 lines of code at a time to ensure you have enough context.
- If a patch is not applied correctly, attempt to reapply it.
- Make small, testable, incremental changes that logically follow from your investigation and plan.
- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.

## 7. Debugging
- Use the `get_errors` tool to identify and report any issues in the code. This tool replaces the previously used `#problems` tool.
- Use the `get_errors` tool to check for any problems in the code
- Make code changes only if you have high confidence they can solve the problem
- When debugging, try to determine the root cause rather than addressing symptoms
- Debug for as long as needed to identify the root cause and identify a fix
Expand All @@ -106,11 +108,12 @@ Use the following format to create a todo list:
- [ ] Step 3: Description of the third step
```

Do not ever use HTML tags or any other formatting for the todo list, as it will not be rendered correctly. Always use the markdown format shown above.
Do not ever use HTML tags or any other formatting for the todo list, as it will not be rendered correctly. Always use the markdown format shown above. Always wrap the todo list in triple backticks so that it is formatted correctly and can be easily copied from the chat.

# Communication Guidelines
Always communicate clearly and concisely in a casual, friendly yet professional tone.
Always show the completed todo list to the user as the last item in your message, so that they can see that you have addressed all of the steps.

# Communication Guidelines
Always communicate clearly and concisely in a casual, friendly yet professional tone.
<examples>
"Let me fetch the URL you provided to gather more information."
"Ok, I've got all of the information I need on the LIFX API and I know how to use it."
Expand All @@ -119,3 +122,44 @@ Always communicate clearly and concisely in a casual, friendly yet professional
"OK! Now let's run the tests to make sure everything is working correctly."
"Whelp - I see we have some problems. Let's fix those up."
</examples>

- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler.
- Always write code directly to the correct files.
- Do not display code to the user unless they specifically ask for it.
- Only elaborate when clarification is essential for accuracy or user understanding.

# Memory
You have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it.

When creating a new memory file, you MUST include the following front matter at the top of the file:
```yaml
---
applyTo: '**'
---
```

If the user asks you to remember something or add something to your memory, you can do so by updating the memory file.

# Reading Files and Folders

**Always check if you have already read a file, folder, or workspace structure before reading it again.**

- If you have already read the content and it has not changed, do NOT re-read it.
- Only re-read files or folders if:
- You suspect the content has changed since your last read.
- You have made edits to the file or folder.
- You encounter an error that suggests the context may be stale or incomplete.
- Use your internal memory and previous context to avoid redundant reads.
- This will save time, reduce unnecessary operations, and make your workflow more efficient.

# Writing Prompts
If you are asked to write a prompt, you should always generate the prompt in markdown format.

If you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.

Remember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.

# Git
If the user tells you to stage and commit, you may do so.

You are NEVER allowed to stage and commit files automatically.
117 changes: 117 additions & 0 deletions .github/instructions/frontend-svelte.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,81 @@ applyTo: "src/Exceptionless.Web/ClientApp/**/*.svelte"
- Use `import { page } from '$app/state'` instead of `'$app/stores'`
- Use snippets `{#snippet ...}` and `{@render ...}` instead of `<slot>` for content projection.

## Asynchronous Components (Experimental)

**Available in Svelte 5.36+ with experimental.async compiler option**

You can now use `await` directly in three places:
- At the top level of a component `<script>`
- In a `$derived` expression
- In template expressions (markup)

## Form Handling with Superforms

### Safe Data Cloning Pattern
Always use the `structuredCloneState()` utility when initializing forms and resetting form data to prevent cache mutation and reactive entanglement:

```svelte
import { structuredCloneState } from '$features/shared/utils/state';

// Form initialization - use structuredCloneState utility
const form = superForm(defaults(structuredCloneState(settings) || new NotificationSettings(), classvalidatorClient(NotificationSettings)), {
// form options...
});

// Form reset in $effect - use structuredCloneState utility
$effect(() => {
if (!$submitting && !$tainted && settings !== previousSettingsRef) {
const clonedSettings = structuredCloneState(settings);
form.reset({ data: clonedSettings, keepMessage: true });
previousSettingsRef = settings;
}
});
```

### Reactive Binding Pattern
For simple reactive bindings to query data, you can override derived values for binding:

```svelte
// Derived value that can be temporarily overridden for binding
let emailNotificationsEnabled = $derived(meQuery.data?.email_notifications_enabled ?? false);

// Sync the derived value when source data changes
$effect(() => {
emailNotificationsEnabled = meQuery.data?.email_notifications_enabled ?? false;
});
```

```svelte
<!-- Direct binding works - temporarily overrides derived value -->
<Switch bind:checked={emailNotificationsEnabled} />
```

**Note:** This pattern uses Svelte 5's ability to override derived values (available since v5.25). The derived value automatically recalculates when dependencies change, but can be temporarily overridden for UI binding. The `$effect` ensures the local state resyncs when the source data changes.

### Why These Patterns?
- **Prevents Cache Mutation**: `structuredCloneState()` creates independent copies that don't affect cached data
- **Reactive Safety**: Uses `$state.snapshot()` internally for non-reactive snapshots, preventing unintended dependencies
- **Form Isolation**: Each form gets its own copy of data, preventing cross-contamination
- **Auto-Reset**: Local state automatically resets when source data changes
- **Bindable**: Creates writable state for form controls and UI components
- **Predictable Behavior**: Ensures consistent form state management across all scenarios
- **Type Safety**: Utility provides proper TypeScript types and handles undefined/null gracefully

### Reference Comparison for Resets
Use object reference comparison instead of JSON stringification for performance:
```svelte
// ✅ Good - Reference comparison
if (settings !== previousSettingsRef) {
// reset logic
}

// ❌ Avoid - JSON comparison (slower)
if (JSON.stringify(settings) !== JSON.stringify(previousSettings)) {
// reset logic
}
```

## Event Handling

- All single-line control statements must be enclosed in curly braces
Expand All @@ -24,6 +99,48 @@ applyTo: "src/Exceptionless.Web/ClientApp/**/*.svelte"
- Use the Composite Component Pattern
- Organize components within vertical slices aligned with API controllers

## Dialog Component Patterns

### Naming Conventions
- Dialog state variables should use `open[ComponentName]Dialog` pattern (e.g., `openSuspendOrganizationDialog`, `openMarkStackDiscardedDialog`)
- Avoid generic names like `showDialog` or `isOpen`

### Event Handlers
- Use inline arrow functions for opening dialogs: `onclick={() => (openDialogName = true)}`
- Avoid creating separate handler functions just to set state to true
- Create separate async functions only for complex operations (API calls, validation, etc.)

### Conditional Rendering
- Always wrap dialogs in `{#if}` blocks: `{#if openDialogName} <Dialog /> {/if}`
- This prevents unnecessary DOM creation and improves performance

### API Integration
- Import and use existing interface types from API files (e.g., `SuspendOrganizationParams`)
- Don't create inline types when proper interfaces exist
- Create options files following the `DropdownItem<EnumType>[]` pattern in `options.ts`

### Example Pattern
```svelte
<script lang="ts">
import type { ApiParamsInterface } from '$features/module/api.svelte';
import { optionsArray } from '$features/module/options';

let openMyActionDialog = $state(false);

async function performAction(params: ApiParamsInterface) {
// API call logic here
}
</script>

<Button onclick={() => (openMyActionDialog = true)}>
Action Label
</Button>

{#if openMyActionDialog}
<MyActionDialog bind:open={openMyActionDialog} action={performAction} />
{/if}
```

## Accessibility

- Ensure excellent keyboard navigation for all interactions
Expand Down
13 changes: 13 additions & 0 deletions .github/instructions/frontend.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ Located in the `src/Exceptionless.Web/ClientApp` directory.
- Organize code into vertical slices (e.g., features aligned with API controllers) and maintain shared components in a central folder.
- Reexport generated code `src/Exceptionless.Web/ClientApp/src/lib/generated` from the respective feature models folder.
- Always look for models in generated code before creating new models.
- **CRITICAL**: Always examine existing similar components and follow their exact patterns before creating new components.
- Study naming conventions, state management, and file organization from existing examples.
- For dialogs, examine `/components/dialogs/` folders for established patterns.
- For options/dropdowns, check for existing `options.ts` files following the `DropdownItem<EnumType>[]` pattern.

## UI & Accessibility

Expand All @@ -37,3 +41,12 @@ Located in the `src/Exceptionless.Web/ClientApp` directory.

- Use TanStack Query for all API calls centralized in an `api.svelte.ts` file.
- Leverage `@exceptionless/fetchclient` for network operations.
- **API function naming**: Prefix function names with HTTP verbs (e.g., `postOrganization`, `patchOrganization`, `deleteOrganization`)
- **API interfaces**: Follow the pattern `[HttpVerb][Resource][Params|Request]` (e.g., `PostOrganizationParams`, `DeleteOrganizationRequest`)

## Type Safety & Interfaces

- **Always use existing API interfaces** instead of creating inline types (e.g., use `SuspendOrganizationParams` from `api.svelte.ts`)
- Import type definitions from their proper modules (`api.svelte.ts`, `models.ts`, `options.ts`)
- Create `options.ts` files for dropdown/select data following the `DropdownItem<EnumType>[]` pattern
- Check existing type definitions before creating new ones to avoid duplication
2 changes: 1 addition & 1 deletion src/Exceptionless.Core/Authorization/AuthorizationRoles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ public static class AuthorizationRoles
public const string User = "user";
public const string GlobalAdminPolicy = nameof(GlobalAdminPolicy);
public const string GlobalAdmin = "global";
public static readonly string[] AllScopes = ["client", "user", "global"];
public static readonly ISet<string> AllScopes = new HashSet<string>([Client, User, GlobalAdmin]);
}
6 changes: 3 additions & 3 deletions src/Exceptionless.Core/Jobs/CleanupDataJob.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ private async Task CleanupSoftDeletedOrganizationsAsync(JobContext context)
}

// Sleep so we are not hammering the backend.
await Task.Delay(TimeSpan.FromSeconds(2.5));
await Task.Delay(TimeSpan.FromSeconds(2.5), _timeProvider);
}

if (context.CancellationToken.IsCancellationRequested || !await organizationResults.NextPageAsync())
Expand Down Expand Up @@ -145,7 +145,7 @@ private async Task CleanupSoftDeletedProjectsAsync(JobContext context)
}

// Sleep so we are not hammering the backend.
await Task.Delay(TimeSpan.FromSeconds(2.5));
await Task.Delay(TimeSpan.FromSeconds(2.5), _timeProvider);
}

if (context.CancellationToken.IsCancellationRequested || !await projectResults.NextPageAsync())
Expand Down Expand Up @@ -250,7 +250,7 @@ private async Task EnforceRetentionAsync(JobContext context)
}

// Sleep so we are not hammering the backend.
await Task.Delay(TimeSpan.FromSeconds(2.5));
await Task.Delay(TimeSpan.FromSeconds(2.5), _timeProvider);
}

if (context.CancellationToken.IsCancellationRequested || !await results.NextPageAsync())
Expand Down
2 changes: 1 addition & 1 deletion src/Exceptionless.Core/Jobs/CleanupOrphanedDataJob.cs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ public async Task FixDuplicateStacks(JobContext context)
else if (attempts > 5)
delay = TimeSpan.FromMilliseconds(250);

await Task.Delay(delay);
await Task.Delay(delay, _timeProvider);
} while (true);

_logger.LogInformation("Migrated stack events: Target={TargetId} Events={UpdatedEvents} Dupes={DuplicateIds}", targetStack.Id, affectedRecords, duplicateStacks.Select(s => s.Id));
Expand Down
Loading
Loading