Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
172a32a
refactor: migrate project settings to TS and break into smaller compo…
talissoncosta Nov 19, 2025
3308c4e
refactor: standardize organisationId type and improve error handling
talissoncosta Nov 19, 2025
856e5fe
refactor: add check on update func and clean up comments
talissoncosta Nov 19, 2025
22f550a
feat: add small transition on hide/show component
talissoncosta Nov 19, 2025
0b2c799
fix: add disable state for delete project button
talissoncosta Nov 19, 2025
4ef5fc9
fix: remove unused types
talissoncosta Nov 19, 2025
f9f54fe
fix: fix permissions data
talissoncosta Nov 19, 2025
74139ce
refactor: simplify import tab passing project name and id
talissoncosta Nov 19, 2025
a0eacd3
refactor: create useUpdateProjectWithToast custom hook
talissoncosta Nov 19, 2025
e138bfb
refactor: migrate settings components to use custom hook
talissoncosta Nov 19, 2025
0f5ebc1
refactor: use Pick for UpdateProjectBody type definition
talissoncosta Nov 20, 2025
429dba2
feat: add optimistic updates to project mutation
talissoncosta Nov 20, 2025
72f27aa
refactor: remove manual state syncing from project settings components
talissoncosta Nov 20, 2025
008db88
refactor: extract change requests setting into separate component
talissoncosta Nov 20, 2025
1031e13
refactor: remove unnecessary useCallback wrappers
talissoncosta Nov 20, 2025
5e23c44
refactor: small adjusts
talissoncosta Nov 20, 2025
1d1cc06
fix: sync OrganisationStore after project updates for navbar refresh
talissoncosta Nov 20, 2025
3eec61d
chore: add --fix on lint-staged
talissoncosta Nov 20, 2025
8825bf2
fix: address PR review comments - type safety and code organization
talissoncosta Nov 20, 2025
3a65fb5
fix: don't re-throw error
talissoncosta Nov 20, 2025
bae75e6
fix: adjust index files on internal pages
talissoncosta Nov 21, 2025
e145a96
fix: restore original toast messages and button states in project set…
talissoncosta Nov 21, 2025
87fd0bc
fix: correct inverted logic in case sensitivity toggle
talissoncosta Nov 21, 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
56 changes: 56 additions & 0 deletions frontend/common/services/useProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,71 @@ export const projectService = service
.enhanceEndpoints({ addTagTypes: ['Project'] })
.injectEndpoints({
endpoints: (builder) => ({
deleteProject: builder.mutation<void, Req['deleteProject']>({
invalidatesTags: [{ id: 'LIST', type: 'Project' }],
query: ({ id }: Req['deleteProject']) => ({
method: 'DELETE',
url: `projects/${id}/`,
}),
}),
getProject: builder.query<Res['project'], Req['getProject']>({
providesTags: (res) => [{ id: res?.id, type: 'Project' }],
query: (query: Req['getProject']) => ({
url: `projects/${query.id}/`,
}),
}),
getProjectPermissions: builder.query<
Res['userPermissions'],
Req['getProjectPermissions']
>({
query: ({ projectId }: Req['getProjectPermissions']) => ({
url: `projects/${projectId}/user-permissions/`,
}),
}),
getProjects: builder.query<Res['projects'], Req['getProjects']>({
providesTags: [{ id: 'LIST', type: 'Project' }],
query: (data) => ({
url: `projects/?organisation=${data.organisationId}`,
}),
transformResponse: (res) => sortBy(res, (v) => v.name.toLowerCase()),
}),
migrateProject: builder.mutation<void, Req['migrateProject']>({
invalidatesTags: (res, error, { id }) => [{ id, type: 'Project' }],
query: ({ id }: Req['migrateProject']) => ({
method: 'POST',
url: `projects/${id}/migrate-to-edge/`,
}),
}),
updateProject: builder.mutation<Res['project'], Req['updateProject']>({
invalidatesTags: (res) => [
{ id: res?.id, type: 'Project' },
{ id: 'LIST', type: 'Project' },
],
async onQueryStarted({ body, id }, { dispatch, queryFulfilled }) {
// Optimistically update the cache before server responds
const patchResult = dispatch(
projectService.util.updateQueryData(
'getProject',
{ id },
(draft) => {
Object.assign(draft, body)
},
),
)

try {
await queryFulfilled
} catch {
// Automatically rollback on error
patchResult.undo()
}
},
query: ({ body, id }: Req['updateProject']) => ({
body,
method: 'PUT',
url: `projects/${id}/`,
}),
}),
// END OF ENDPOINTS
}),
})
Expand Down Expand Up @@ -47,8 +99,12 @@ export async function getProject(
// END OF FUNCTION_EXPORTS

export const {
useDeleteProjectMutation,
useGetProjectPermissionsQuery,
useGetProjectQuery,
useGetProjectsQuery,
useMigrateProjectMutation,
useUpdateProjectMutation,
// END OF EXPORTS
} = projectService

Expand Down
16 changes: 15 additions & 1 deletion frontend/common/types/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
UserGroup,
AttributeName,
Identity,
ChangeRequest,
ProjectChangeRequest,
Role,
RolePermission,
Expand All @@ -27,6 +26,17 @@ import {
} from './responses'
import { UtmsType } from './utms'

export type UpdateProjectBody = {
name: string
hide_disabled_flags?: boolean
prevent_flag_defaults?: boolean
enable_realtime_updates?: boolean
minimum_change_request_approvals?: number | null
stale_flags_limit_days?: number | null
only_allow_lower_case_feature_names?: boolean
feature_name_regex?: string | null
}

export type PagedRequest<T> = T & {
page?: number
page_size?: number
Expand Down Expand Up @@ -580,6 +590,10 @@ export type Req = {
id: string
}
getProject: { id: string }
updateProject: { id: string; body: UpdateProjectBody }
deleteProject: { id: string }
migrateProject: { id: string }
getProjectPermissions: { projectId: string }
createGroup: {
orgId: string
data: Omit<UserGroup, 'id' | 'users'>
Expand Down
4 changes: 3 additions & 1 deletion frontend/common/types/responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ export type Project = {
total_features?: number
stale_flags_limit_days?: number
total_segments?: number
only_allow_lower_case_feature_names?: boolean
feature_name_regex?: string | null
environments: Environment[]
}
export type ImportStrategy = 'SKIP' | 'OVERWRITE_DESTRUCTIVE'
Expand Down Expand Up @@ -1104,7 +1106,7 @@ export type Res = {
}
profile: User
onboarding: {}
userPermissions: UserPermissions
userPermissions: UserPermission[]
releasePipelines: PagedResponse<ReleasePipeline>
releasePipeline: SingleReleasePipeline
pipelineStages: PagedResponse<PipelineStage>
Expand Down
13 changes: 13 additions & 0 deletions frontend/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,24 @@ declare global {
const Select: typeof _Select
const Column: typeof Component
const Loader: typeof Component
const Input: typeof Component
const Button: typeof Component
const E2E: boolean
const closeModal: () => void
const closeModal2: () => void
const toast: (message: string) => void
const Tooltip: FC<TooltipProps>
const API: {
trackPage: (title: string) => void
trackEvent: (data: {
category: string
event: string
label?: string
extra?: Record<string, any>
}) => void
trackTraits: (traits: Record<string, any>) => void
[key: string]: any
}
interface Window {
$crisp: Crisp
engagement: {
Expand Down
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,6 @@
"typescript": "4.6.4"
},
"lint-staged": {
"*.{js,ts,tsx}": "eslint"
"*.{js,ts,tsx}": "eslint --fix"
}
}
Loading
Loading