override cache for defaults

This commit is contained in:
Nate Kelley 2025-07-18 13:04:12 -06:00
parent 8988837248
commit aa34a56f40
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
8 changed files with 119 additions and 106 deletions

View File

@ -1,4 +1,6 @@
import type { DEFAULT_COLOR_PALETTE_ID as DEFAULT_COLOR_PALETTE_ID_DATABASE } from '@buster/database';
import { DEFAULT_CHART_THEME } from '@buster/server-shared/metrics';
import type { ColorPalette } from '@buster/server-shared/organization';
const SOFT_THEME = [
@ -309,7 +311,7 @@ const PINK_THEME = [
'#ad1457',
];
export const DEFAULT_COLOR_PALETTE_ID = '__DEFAULT__';
export const DEFAULT_COLOR_PALETTE_ID: typeof DEFAULT_COLOR_PALETTE_ID_DATABASE = '__DEFAULT__';
const createDefaultId = (name: string, index: number) => {
return `${DEFAULT_COLOR_PALETTE_ID}${name.toLowerCase().replace(/ /g, '-')}-${index}`;
@ -430,3 +432,5 @@ export const MONOCHROME_THEMES = [
}));
export const ALL_THEMES: ColorPalette[] = [...COLORFUL_THEMES, ...MONOCHROME_THEMES];
export const ALL_DICTIONARY_THEMES: ColorPalette[] = ALL_THEMES;

View File

@ -1,11 +1,11 @@
import type { ColorPaletteDictionariesResponse } from '@buster/server-shared/dictionary';
import { Hono } from 'hono';
import { ALL_THEMES } from './config';
import { ALL_DICTIONARY_THEMES } from './config';
const app = new Hono();
app.get('/', async (c) => {
const response: ColorPaletteDictionariesResponse = ALL_THEMES;
const response: ColorPaletteDictionariesResponse = ALL_DICTIONARY_THEMES;
return c.json(response);
});

View File

@ -1,6 +1,5 @@
import type { OrganizationRole } from '@buster/server-shared/organization';
import { OrganizationRoleEnum } from '@buster/server-shared/organization';
export const isOrganizationAdmin = (role: OrganizationRole) => {
return role === OrganizationRoleEnum.workspace_admin || role === OrganizationRoleEnum.data_admin;
return role === 'workspace_admin' || role === 'data_admin';
};

View File

@ -9,4 +9,4 @@ export {
type UserToOrganization,
} from './organizations';
export { updateOrganization } from './update-organization';
export { updateOrganization, type DEFAULT_COLOR_PALETTE_ID } from './update-organization';

View File

@ -1,100 +0,0 @@
import { and, eq, isNull } from 'drizzle-orm';
import { z } from 'zod';
import { db } from '../../connection';
import { organizations } from '../../schema';
import type { OrganizationColorPalettes } from '../../schema-types';
// Hex color validation schema for 3 or 6 digit hex codes
const HexColorSchema = z
.string()
.regex(
/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/,
'Must be a valid 3 or 6 digit hex color code (e.g., #fff or #ffffff)'
);
// Organization Color Palette schema
const OrganizationColorPaletteSchema = z.object({
id: z.string().min(1).max(255),
colors: z.array(HexColorSchema),
name: z.string().min(1).max(255),
});
// Organization Color Palettes schema (extracted to its own schema)
const OrganizationColorPalettesSchema = z
.object({
selectedId: z.string().min(1).max(255).nullable(),
palettes: z.array(OrganizationColorPaletteSchema).refine(
(palettes) => {
if (!palettes || palettes.length === 0) return true;
const ids = palettes.map((palette) => palette.id);
const uniqueIds = new Set(ids);
return ids.length === uniqueIds.size;
},
{
message: 'All color palette IDs must be unique',
}
),
})
.refine(
(data) => {
// If selectedId is null, no validation needed
if (data.selectedId === null) return true;
// If selectedId is provided, it must exist in the palettes array
const paletteIds = data.palettes.map((palette) => palette.id);
return paletteIds.includes(data.selectedId);
},
{
message: 'Selected ID must exist in the palettes array',
path: ['selectedId'], // Point the error to the selectedId field
}
);
// Input validation schema
const UpdateOrganizationInputSchema = z.object({
organizationId: z.string().uuid('Organization ID must be a valid UUID'),
organizationColorPalettes: OrganizationColorPalettesSchema,
});
type UpdateOrganizationInput = z.infer<typeof UpdateOrganizationInputSchema>;
/**
* Updates organization settings
* Currently supports updating organization color palettes
*/
export const updateOrganization = async (params: UpdateOrganizationInput): Promise<void> => {
// Validate and destructure input
const { organizationId, organizationColorPalettes } = UpdateOrganizationInputSchema.parse(params);
try {
// Build update data
const updateData: {
updatedAt: string;
organizationColorPalettes?: OrganizationColorPalettes;
} = {
updatedAt: new Date().toISOString(),
};
if (organizationColorPalettes !== undefined) {
updateData.organizationColorPalettes = organizationColorPalettes;
}
// Update organization in database
await db
.update(organizations)
.set(updateData)
.where(and(eq(organizations.id, organizationId), isNull(organizations.deletedAt)));
} catch (error) {
console.error('Error updating organization:', {
organizationId,
error: error instanceof Error ? error.message : error,
});
// Re-throw with more context
if (error instanceof Error) {
throw error;
}
throw new Error('Failed to update organization');
}
};

View File

@ -0,0 +1,2 @@
export * from './update-organization';
export type { DEFAULT_COLOR_PALETTE_ID } from './organization-color-palettes';

View File

@ -0,0 +1,53 @@
import { z } from 'zod';
export const DEFAULT_COLOR_PALETTE_ID = '__DEFAULT__';
// Hex color validation schema for 3 or 6 digit hex codes
const HexColorSchema = z
.string()
.regex(
/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/,
'Must be a valid 3 or 6 digit hex color code (e.g., #fff or #ffffff)'
);
// Organization Color Palette schema
const OrganizationColorPaletteSchema = z.object({
id: z.string().min(1).max(255),
colors: z.array(HexColorSchema),
name: z.string().min(1).max(255),
});
// Organization Color Palettes schema (extracted to its own schema)
export const OrganizationColorPalettesSchema = z
.object({
selectedId: z.string().min(1).max(255).nullable(),
palettes: z.array(OrganizationColorPaletteSchema).refine(
(palettes) => {
if (!palettes || palettes.length === 0) return true;
const ids = palettes.map((palette) => palette.id);
const uniqueIds = new Set(ids);
return ids.length === uniqueIds.size;
},
{
message: 'All color palette IDs must be unique',
}
),
})
.refine(
(data) => {
// If selectedId is null, no validation needed
console.log('data.selectedId', data.selectedId);
if (data.selectedId === null || data.selectedId.startsWith(DEFAULT_COLOR_PALETTE_ID)) {
return true;
}
// If selectedId is provided, it must exist in the palettes array
const paletteIds = data.palettes.map((palette) => palette.id);
return paletteIds.includes(data.selectedId);
},
{
message:
'Selected ID must exist in the palettes array or be a default palette from the dictionary endpoint',
path: ['selectedId'], // Point the error to the selectedId field
}
);

View File

@ -0,0 +1,55 @@
import { and, eq, isNull } from 'drizzle-orm';
import { z } from 'zod';
import { db } from '../../../connection';
import { organizations } from '../../../schema';
import type { OrganizationColorPalettes } from '../../../schema-types';
import { OrganizationColorPalettesSchema } from './organization-color-palettes';
// Input validation schema
const UpdateOrganizationInputSchema = z.object({
organizationId: z.string().uuid('Organization ID must be a valid UUID'),
organizationColorPalettes: OrganizationColorPalettesSchema,
});
type UpdateOrganizationInput = z.infer<typeof UpdateOrganizationInputSchema>;
/**
* Updates organization settings
* Currently supports updating organization color palettes
*/
export const updateOrganization = async (params: UpdateOrganizationInput): Promise<void> => {
// Validate and destructure input
const { organizationId, organizationColorPalettes } = UpdateOrganizationInputSchema.parse(params);
try {
// Build update data
const updateData: {
updatedAt: string;
organizationColorPalettes?: OrganizationColorPalettes;
} = {
updatedAt: new Date().toISOString(),
};
if (organizationColorPalettes !== undefined) {
updateData.organizationColorPalettes = organizationColorPalettes;
}
// Update organization in database
await db
.update(organizations)
.set(updateData)
.where(and(eq(organizations.id, organizationId), isNull(organizations.deletedAt)));
} catch (error) {
console.error('Error updating organization:', {
organizationId,
error: error instanceof Error ? error.message : error,
});
// Re-throw with more context
if (error instanceof Error) {
throw error;
}
throw new Error('Failed to update organization');
}
};