Skip to content

Commit 23e3be4

Browse files
committed
Merge branch 'refs/heads/main' into chore/rtk-identity-traits
# Conflicts: # frontend/common/types/requests.ts # frontend/web/components/pages/UserPage.tsx
2 parents 0cf996a + 951b216 commit 23e3be4

38 files changed

+1316
-1027
lines changed

.git-blame-ignore-revs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Initial Mypy '# type: ignore' comments dump
2+
# https://github.com/Flagsmith/flagsmith/pull/5119
3+
5de0b425b0ee16b16bfb0fb33b067fa314d040fb
4+
# Linting fixes for frontend
5+
# https://github.com/Flagsmith/flagsmith/pull/5123
6+
1f7083636d3b163588fe9a8b45af289bd40b1a8d

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ repos:
1313
exclude: migrations
1414

1515
- repo: https://github.com/pycqa/flake8
16-
rev: 7.1.1
16+
rev: 7.1.2
1717
hooks:
1818
- id: flake8
1919
name: flake8
@@ -46,7 +46,7 @@ repos:
4646
types: [python]
4747

4848
- repo: https://github.com/python-poetry/poetry
49-
rev: 2.0.1
49+
rev: 2.1.1
5050
hooks:
5151
- id: poetry-check
5252
args: ["-C", "api"]

api/audit/signals.py

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
import typing
23

34
from django.conf import settings
45
from django.db.models.signals import post_save
@@ -18,6 +19,33 @@
1819
logger = logging.getLogger(__name__)
1920

2021

22+
AuditLogIntegrationAttrName = typing.Literal[
23+
"data_dog_config",
24+
"dynatrace_config",
25+
"grafana_config",
26+
"new_relic_config",
27+
"slack_config",
28+
]
29+
30+
31+
def _get_integration_config(
32+
instance: AuditLog,
33+
integration_name: AuditLogIntegrationAttrName,
34+
) -> IntegrationsModel | None:
35+
for relation_name in ("project", "environment", "organisation"):
36+
if hasattr(
37+
related_object := getattr(instance, relation_name),
38+
integration_name,
39+
):
40+
integration_config: IntegrationsModel = getattr(
41+
related_object,
42+
integration_name,
43+
)
44+
if not integration_config.deleted:
45+
return integration_config
46+
return None
47+
48+
2149
@receiver(post_save, sender=AuditLog)
2250
def call_webhooks(sender, instance, **kwargs): # type: ignore[no-untyped-def]
2351
if settings.DISABLE_WEBHOOKS:
@@ -42,18 +70,6 @@ def call_webhooks(sender, instance, **kwargs): # type: ignore[no-untyped-def]
4270
)
4371

4472

45-
def _get_integration_config(
46-
instance: AuditLog, integration_name: str
47-
) -> IntegrationsModel | None:
48-
if hasattr(project := instance.project, integration_name):
49-
return getattr(project, integration_name) # type: ignore[no-any-return]
50-
if hasattr(environment := instance.environment, integration_name):
51-
return getattr(environment, integration_name) # type: ignore[no-any-return]
52-
if hasattr(organisation := instance.organisation, integration_name):
53-
return getattr(organisation, integration_name) # type: ignore[no-any-return]
54-
return None
55-
56-
5773
def track_only_feature_related_events(signal_function): # type: ignore[no-untyped-def]
5874
def signal_wrapper(sender, instance, **kwargs): # type: ignore[no-untyped-def]
5975
# Only handle Feature related changes

api/tests/unit/audit/test_unit_audit_signals.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,32 @@ def test_send_audit_log_event_to_grafana__organisation_grafana_config__calls_exp
168168
)
169169

170170

171+
def test_send_audit_log_event_to_grafana__organisation_grafana_config__deleted__doesnt_call(
172+
mocker: MockerFixture,
173+
organisation: Organisation,
174+
project: Project,
175+
) -> None:
176+
# Given
177+
audit_log_record = AuditLog.objects.create(
178+
project=project,
179+
related_object_type=RelatedObjectType.FEATURE.name,
180+
)
181+
grafana_wrapper_mock = mocker.patch("audit.signals.GrafanaWrapper", autospec=True)
182+
183+
grafana_config = GrafanaOrganisationConfiguration.objects.create(
184+
organisation=organisation,
185+
base_url="test.com",
186+
api_key="test",
187+
)
188+
grafana_config.delete()
189+
190+
# When
191+
send_audit_log_event_to_grafana(AuditLog, audit_log_record)
192+
193+
# Then
194+
grafana_wrapper_mock.assert_not_called()
195+
196+
171197
@responses.activate
172198
def test_send_environment_feature_version_audit_log_event_to_grafana(
173199
tagged_feature: Feature,

frontend/common/constants.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ const Constants = {
363363
},
364364
},
365365
exampleAuditWebhook: `{
366-
"created_date": "2020-02-23T17:30:57.006318Z",
366+
"created_date": "2020-02-23T17:30:57.006318Z",
367367
"log": "New Flag / Remote Config created: my_feature",
368368
"author": {
369369
"id": 3,
@@ -435,6 +435,15 @@ const Constants = {
435435
},
436436
"event_type": "FLAG_UPDATED"
437437
}`,
438+
featurePanelTabs: {
439+
ANALYTICS: 'analytics',
440+
HISTORY: 'history',
441+
IDENTITY_OVERRIDES: 'identity-overrides',
442+
LINKS: 'links',
443+
SEGMENT_OVERRIDES: 'segment-overrides',
444+
SETTINGS: 'settings',
445+
VALUE: 'value',
446+
},
438447
forms: {
439448
maxLength: {
440449
'FEATURE_ID': 150,

frontend/common/dispatcher/action-constants.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ const Actions = Object.assign({}, require('./base/_action-constants'), {
3030
'GET_FEATURE_USAGE': 'GET_FEATURE_USAGE',
3131
'GET_FLAGS': 'GET_FLAGS',
3232
'GET_IDENTITY': 'GET_IDENTITY',
33-
'GET_IDENTITY_SEGMENTS': 'GET_IDENTITY_SEGMENTS',
3433
'GET_ORGANISATION': 'GET_ORGANISATION',
3534
'GET_PROJECT': 'GET_PROJECT',
3635
'INVALIDATE_INVITE_LINK': 'INVALIDATE_INVITE_LINK',

frontend/common/dispatcher/app-actions.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -246,13 +246,6 @@ const AppActions = Object.assign({}, require('./base/_app-actions'), {
246246
id,
247247
})
248248
},
249-
getIdentitySegments(projectId, id) {
250-
Dispatcher.handleViewAction({
251-
actionType: Actions.GET_IDENTITY_SEGMENTS,
252-
id,
253-
projectId,
254-
})
255-
},
256249
getOrganisation(organisationId) {
257250
Dispatcher.handleViewAction({
258251
actionType: Actions.GET_ORGANISATION,

frontend/common/providers/IdentitySegmentsProvider.js

Lines changed: 0 additions & 42 deletions
This file was deleted.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { Res } from 'common/types/responses'
2+
import { Req } from 'common/types/requests'
3+
import { service } from 'common/service'
4+
import Utils from 'common/utils/utils'
5+
import transformCorePaging from 'common/transformCorePaging'
6+
import { sortBy } from 'lodash'
7+
8+
export const identitySegmentService = service
9+
.enhanceEndpoints({ addTagTypes: ['IdentitySegment'] })
10+
.injectEndpoints({
11+
endpoints: (builder) => ({
12+
getIdentitySegments: builder.query<
13+
Res['identitySegments'],
14+
Req['getIdentitySegments']
15+
>({
16+
providesTags: (res) => [{ id: res?.id, type: 'IdentitySegment' }],
17+
query: ({ projectId, ...query }: Req['getIdentitySegments']) => ({
18+
url: `/projects/${projectId}/segments/?${Utils.toParam(query)}`,
19+
}),
20+
transformResponse: (
21+
res: Res['identitySegments'],
22+
_,
23+
req: Req['getIdentitySegments'],
24+
) =>
25+
transformCorePaging(req, {
26+
...res,
27+
results: sortBy(res.results, 'name'),
28+
}),
29+
}),
30+
// END OF ENDPOINTS
31+
}),
32+
})
33+
34+
export async function getIdentitySegments(
35+
store: any,
36+
data: Req['getIdentitySegments'],
37+
options?: Parameters<
38+
typeof identitySegmentService.endpoints.getIdentitySegments.initiate
39+
>[1],
40+
) {
41+
return store.dispatch(
42+
identitySegmentService.endpoints.getIdentitySegments.initiate(
43+
data,
44+
options,
45+
),
46+
)
47+
}
48+
// END OF FUNCTION_EXPORTS
49+
50+
export const {
51+
useGetIdentitySegmentsQuery,
52+
// END OF EXPORTS
53+
} = identitySegmentService
54+
55+
/* Usage examples:
56+
const { data, isLoading } = useGetIdentitySegmentsQuery({ id: 2 }, {}) //get hook
57+
const [createIdentitySegments, { isLoading, data, isSuccess }] = useCreateIdentitySegmentsMutation() //create hook
58+
identitySegmentService.endpoints.getIdentitySegments.select({id: 2})(store.getState()) //access data from any function
59+
*/

frontend/common/stores/feature-list-store.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -670,12 +670,17 @@ const controller = {
670670
)
671671
}
672672
})
673+
return updatedChangeRequest
673674
},
674675
)
675676
})
676677

677-
Promise.all([prom]).then(() => {
678-
store.saved({ changeRequest: true, isCreate: true })
678+
Promise.all([prom]).then(([updatedChangeRequest]) => {
679+
store.saved({
680+
changeRequest: true,
681+
isCreate: true,
682+
updatedChangeRequest,
683+
})
679684
})
680685
} catch (e) {
681686
API.ajaxHandler(store, e)
@@ -975,7 +980,7 @@ const controller = {
975980

976981
const store = Object.assign({}, BaseStore, {
977982
getEnvironmentFlags() {
978-
return store.model && store.model.keyedEnvironmentFeatures
983+
return store?.model?.keyedEnvironmentFeatures
979984
},
980985
getFeatureUsage() {
981986
return store.model && store.model.usageData

frontend/common/stores/identity-segments-store.js

Lines changed: 0 additions & 46 deletions
This file was deleted.

frontend/common/types/requests.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,5 +593,10 @@ export type Req = {
593593
use_edge_identities: boolean
594594
data: Omit<IdentityTrait, 'trait_value'>
595595
}
596+
getIdentitySegments: PagedRequest<{
597+
q?: string
598+
identity: string
599+
projectId: string
600+
}>
596601
// END OF TYPES
597602
}

frontend/common/types/responses.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -456,18 +456,17 @@ export type ProjectFlag = {
456456

457457
export type FeatureListProviderData = {
458458
projectFlags: ProjectFlag[] | null
459-
environmentFlags: FeatureState[] | null
459+
environmentFlags: Record<number, FeatureState> | undefined
460460
error: boolean
461461
isLoading: boolean
462462
}
463463

464464
export type FeatureListProviderActions = {
465465
toggleFlag: (
466-
index: number,
467-
environments: Environment[],
468-
comment: string | null,
469-
environmentFlags: FeatureState[],
470-
projectFlags: ProjectFlag[],
466+
projectId: string,
467+
environmentId: string,
468+
projectFlag: ProjectFlag,
469+
environmentFlags: FeatureState | undefined,
471470
) => void
472471
removeFlag: (projectId: string, projectFlag: ProjectFlag) => void
473472
}
@@ -802,6 +801,7 @@ export type Res = {
802801
metadata_xml: string
803802
}
804803
samlAttributeMapping: PagedResponse<SAMLAttributeMapping>
804+
identitySegments: PagedResponse<Segment>
805805
organisationWebhooks: PagedResponse<Webhook>
806806
identityTrait: { id: string }
807807
identityTraits: IdentityTrait[]

0 commit comments

Comments
 (0)