Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
133 commits
Select commit Hold shift + click to select a range
4011328
Typo
kyle-ssg Jan 13, 2026
4e3f18e
Fix alert infinite callback
kyle-ssg Jan 13, 2026
08b2d34
feat: edit versioned change request (#6368)
kyle-ssg Jan 16, 2026
a9d9be3
Merge branch 'main' into chore/create-flag-migration
kyle-ssg Jan 16, 2026
a0960f3
Fix conflict
kyle-ssg Jan 16, 2026
272cce3
Pass identity override to variation options
kyle-ssg Jan 20, 2026
2a5ce5c
Adjust feature state prop
kyle-ssg Jan 20, 2026
474689b
Merge branch 'main' into chore/create-flag-migration
kyle-ssg Jan 20, 2026
74b83fa
Simplify create feature for identity/environment
kyle-ssg Jan 20, 2026
56d52ed
Playwright
kyle-ssg Jan 20, 2026
c9f792e
Playwright
kyle-ssg Jan 20, 2026
a50bb05
Remove unused tests
kyle-ssg Jan 20, 2026
155a2c6
Merge branch 'main' into chore/playwright
kyle-ssg Jan 20, 2026
184194e
Merge package lock
kyle-ssg Jan 20, 2026
6448d43
Use playwright's firefox in dockerfile
kyle-ssg Jan 20, 2026
00ef9f7
Add frontend makefile logging, remove apt-get line
kyle-ssg Jan 20, 2026
0606454
re-add "tags" to tests
kyle-ssg Jan 20, 2026
5ccaa96
Add health check prior to teardown
kyle-ssg Jan 20, 2026
145056b
Add health check prior to teardown
kyle-ssg Jan 20, 2026
bab12a1
Add health check prior to teardown
kyle-ssg Jan 20, 2026
97adfcb
Improve logging, add sticky comment, add artifcats
kyle-ssg Jan 20, 2026
9bcb51d
Fix duplicate artifacts / race conditions
kyle-ssg Jan 20, 2026
3058590
improve artifacts
kyle-ssg Jan 21, 2026
8bfd940
improve artifacts
kyle-ssg Jan 21, 2026
ae098f8
improve tests
kyle-ssg Jan 21, 2026
36e733e
fix duplicate artifact names, only upload artifacts on failure
kyle-ssg Jan 21, 2026
72e262e
Remove testcafe stuff
kyle-ssg Jan 21, 2026
c28be83
Fix piping
kyle-ssg Jan 21, 2026
7397500
Cut down noise
kyle-ssg Jan 21, 2026
72a9a42
Revert teardown token logic
kyle-ssg Jan 21, 2026
a7ad899
Cut down noise, add success comment
kyle-ssg Jan 21, 2026
42c03de
Cut down noise / stability
kyle-ssg Jan 21, 2026
484ee15
Merge branch 'main' into chore/playwright
kyle-ssg Jan 21, 2026
8d9290f
Better retrying / add quiet mode and skip bundle
kyle-ssg Jan 21, 2026
ea337d6
Better retrying / add quiet mode and skip bundle
kyle-ssg Jan 21, 2026
4b6c08a
Fix piping
kyle-ssg Jan 21, 2026
74f3c4d
Fix piping
kyle-ssg Jan 21, 2026
b751344
Fix piping
kyle-ssg Jan 21, 2026
365e8cb
Replace index based lookups with text
kyle-ssg Jan 21, 2026
848435d
refactor(e2e): Replace index-based feature lookups with name-based lo…
kyle-ssg Jan 22, 2026
da2535a
Replace index based lookups with text
kyle-ssg Jan 22, 2026
4b498cb
add ee tests
kyle-ssg Jan 22, 2026
20381b5
Improve commands
kyle-ssg Jan 22, 2026
720f05e
Add better context and a REPEAT mode
kyle-ssg Jan 28, 2026
3ae6241
Refactor
kyle-ssg Jan 28, 2026
10ae51e
improve segment test
kyle-ssg Jan 28, 2026
c633e48
Improve readme and commands so that you can do /e2e 10 to run 10x
kyle-ssg Jan 28, 2026
7d1e121
Improve readmes, add test:report script
kyle-ssg Jan 28, 2026
7a800f4
Bump retries to 2
kyle-ssg Jan 28, 2026
d099d98
Don't run test:report in ci on failures
kyle-ssg Jan 28, 2026
b6a60ce
Only show report on failure outside of ci
kyle-ssg Jan 28, 2026
b3151e7
Remove interactive elements from run-with-retry, clean up context dup…
kyle-ssg Jan 28, 2026
6f2fb4b
revert docker-compose
kyle-ssg Jan 28, 2026
892198f
disable modal transitions in e2e
kyle-ssg Jan 28, 2026
1774f79
Neaten log helper
kyle-ssg Jan 29, 2026
21ea1ee
Split out test hepers
kyle-ssg Jan 29, 2026
571c031
Move command and context to frontend
kyle-ssg Jan 29, 2026
41cf11f
Update frontend/e2e/teardown.ts
kyle-ssg Jan 30, 2026
e99d912
Avoid focus inputs in e2e, select projects by name
kyle-ssg Jan 30, 2026
6180df1
Merge remote-tracking branch 'origin/chore/playwright' into chore/pla…
kyle-ssg Jan 30, 2026
d360e79
Avoid focus inputs in e2e, select projects by name
kyle-ssg Jan 30, 2026
1d3a95e
Fix conflicts
kyle-ssg Jan 30, 2026
c1ca0c7
Fix conflicts
kyle-ssg Jan 30, 2026
d1fdb86
Make create project test enterprise
kyle-ssg Jan 30, 2026
de21cd9
Improve feature actions clicking
kyle-ssg Jan 31, 2026
0d1fd77
Update frontend/package.json
kyle-ssg Feb 3, 2026
9d1e48a
Simplify E2E global setup and require auth token
kyle-ssg Feb 3, 2026
e51312b
Refactor extract-failed-tests with cleaner helper functions
kyle-ssg Feb 3, 2026
baebacc
Simplify global teardown and move slack helper to e2e/helpers
kyle-ssg Feb 3, 2026
0bfd7c8
TEMPORARY: Add staging environment to E2E workflow for Slack testing
kyle-ssg Feb 3, 2026
c263ced
Force failure
kyle-ssg Feb 3, 2026
aff2e25
Add debug logging to global teardown for Slack notifications
kyle-ssg Feb 3, 2026
1869faa
Move Slack notifications from test reporter to CI workflow
kyle-ssg Feb 3, 2026
2f55be5
Add E2E test convenience targets and fix API URL env var
kyle-ssg Feb 3, 2026
ec48ccb
Fix top-level await error in Slack notification step
kyle-ssg Feb 3, 2026
9295834
Update E2E documentation with new convenience commands
kyle-ssg Feb 3, 2026
30022ee
Add debug logging to Slack notification step
kyle-ssg Feb 3, 2026
031e1ba
Remove duplicate slack.ts and use existing notifyFailure
kyle-ssg Feb 3, 2026
46eb812
Simplify Slack notification with dedicated script file
kyle-ssg Feb 3, 2026
091f968
Move Slack notification logic into slack-e2e-reporter.ts
kyle-ssg Feb 3, 2026
ce0830a
Add HTML report upload to Slack notifications
kyle-ssg Feb 3, 2026
418142b
Refactor global-setup to reuse teardown logic
kyle-ssg Feb 3, 2026
df5a27b
Install @slack/web-api before running Slack reporter
kyle-ssg Feb 3, 2026
0d1a490
Combine zip and Slack notification steps
kyle-ssg Feb 3, 2026
4143031
Add branch, test type, and failed tests to Slack notification
kyle-ssg Feb 3, 2026
e61717e
Add PR info to Slack notification
kyle-ssg Feb 3, 2026
cc40e29
Make Slack notification more compact
kyle-ssg Feb 3, 2026
38a2712
Fix shell quoting and add http:// to API URL
kyle-ssg Feb 3, 2026
b7c64fc
Add http:// prefix to FLAGSMITH_API_URL
kyle-ssg Feb 3, 2026
0092249
Remove duplicate Playwright HTML Report comment from file upload
kyle-ssg Feb 3, 2026
f6170b0
Remove temporary staging environment from E2E workflow
kyle-ssg Feb 3, 2026
2cf2ff1
Merge remote-tracking branch 'origin/chore/playwright' into chore/pla…
kyle-ssg Feb 3, 2026
f16861c
Remove E2E Last Request/Error markup
kyle-ssg Feb 3, 2026
d783d82
Set frontend X-E2E-Token header to allow for unlimited project creation
kyle-ssg Feb 3, 2026
c2686ba
Revert docker-compose.yml
kyle-ssg Feb 3, 2026
a115445
Merge branch 'main' into chore/playwright
kyle-ssg Feb 3, 2026
cfefdf2
Migrate create flag file
kyle-ssg Feb 3, 2026
1cde29a
simplify e2e run options
kyle-ssg Feb 3, 2026
8b4ce12
Remove test:bundle command
kyle-ssg Feb 3, 2026
67f1962
default e2e to false
kyle-ssg Feb 3, 2026
9df5481
default e2e to false
kyle-ssg Feb 4, 2026
2aec097
Add unique comment identifiers for OSS vs Private Cloud test results
kyle-ssg Feb 4, 2026
c6329b0
Make e2e comments unique by arch
kyle-ssg Feb 4, 2026
9510e45
use report-tag parameter for uniquely identifying playwright comments
kyle-ssg Feb 4, 2026
8a3d436
Improve PR labelling, merge retry results with failures
kyle-ssg Feb 4, 2026
384eb82
Update frontend/e2e/run-with-retry.ts
kyle-ssg Feb 6, 2026
29a0216
Update frontend/package.json
kyle-ssg Feb 6, 2026
e8d85b4
Remove E2E = true
kyle-ssg Feb 6, 2026
58f343a
Merge remote-tracking branch 'origin/chore/playwright' into chore/pla…
kyle-ssg Feb 6, 2026
b2d394e
Merge branch 'main' into chore/playwright
kyle-ssg Feb 6, 2026
0613679
Remove E2E = true, fix package-lock
kyle-ssg Feb 6, 2026
bf63d34
Merge branch 'main' into chore/playwright
kyle-ssg Feb 18, 2026
5df5089
package lock
kyle-ssg Feb 18, 2026
80ad1ef
Fix account personas tests
kyle-ssg Feb 18, 2026
6576bfc
Fix Playwright ui race condition for E2E variable assignment
kyle-ssg Feb 18, 2026
2145de4
Handle production race conditions
kyle-ssg Feb 18, 2026
06f03fc
Merge branch 'main' into chore/playwright
kyle-ssg Feb 25, 2026
b3951bc
Handle production race conditions
kyle-ssg Feb 25, 2026
2116b61
Fix webpack config
kyle-ssg Feb 25, 2026
f738f40
Fix sentry dependency issue
kyle-ssg Feb 25, 2026
4a8b838
Remove duplicate waits
kyle-ssg Feb 25, 2026
95a4716
chore: add feature tests (#6652)
kyle-ssg Feb 25, 2026
8c59abc
Bump typescript, permission type issues
kyle-ssg Feb 25, 2026
ceef160
Add tabs, remove old code, fix types
kyle-ssg Feb 25, 2026
b5a0320
Merge branch 'main' into chore/create-feature-migration-continued
kyle-ssg Mar 11, 2026
b01145d
Migrate flagsmith to @flagsmith/flagsmith and @flagsmith/react-native…
kyle-ssg Mar 11, 2026
5e8777c
Merge branch 'chore/permission-types' into chore/create-feature-migra…
kyle-ssg Mar 11, 2026
d393f10
Migrate create flag
kyle-ssg Mar 11, 2026
8bd06b7
Migrate create flag
kyle-ssg Mar 11, 2026
12f29a8
Fix permission check
kyle-ssg Mar 11, 2026
f1c6066
Fix permission check
kyle-ssg Mar 11, 2026
ba41b02
Comment
kyle-ssg Mar 11, 2026
c99dff2
Update frontend/web/components/modals/create-feature/tabs/IdentityOve…
kyle-ssg Mar 18, 2026
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
4 changes: 3 additions & 1 deletion frontend/common/ES6Component.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = function es6Component(context, onUnmount) {
function es6Component(context, onUnmount) {
context._listeners = []

context.listenTo = function listenTo(store, event, callback) {
Expand Down Expand Up @@ -55,3 +55,5 @@ module.exports = function es6Component(context, onUnmount) {
}
}
}

export default es6Component
2 changes: 1 addition & 1 deletion frontend/common/dispatcher/action-constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,4 @@ const Actions = Object.assign({}, require('./base/_action-constants'), {
})

window.Actions = Actions
module.exports = Actions
export default Actions
3 changes: 1 addition & 2 deletions frontend/common/dispatcher/app-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -376,5 +376,4 @@ const AppActions = Object.assign({}, require('./base/_app-actions'), {
},
})

module.exports = AppActions
window.AppActions = AppActions
export default AppActions
16 changes: 16 additions & 0 deletions frontend/common/hooks/useHasGithubIntegration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import AccountStore from 'common/stores/account-store'
import { useGetGithubIntegrationQuery } from 'common/services/useGithubIntegration'

export function useHasGithubIntegration() {
const organisationId = AccountStore.getOrganisation()?.id
const { data } = useGetGithubIntegrationQuery(
{ organisation_id: organisationId },
{ skip: !organisationId },
)

return {
githubId: data?.results?.[0]?.id ?? '',
hasIntegration: !!data?.results?.length,
organisationId,
}
}
2 changes: 1 addition & 1 deletion frontend/common/providers/FeatureListProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -264,4 +264,4 @@ FeatureListProvider.propTypes = {
onSave: OptionalFunc,
}

module.exports = FeatureListProvider
export default FeatureListProvider
5 changes: 4 additions & 1 deletion frontend/common/types/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,10 @@ export type Req = {
getTags: {
projectId: number
}
createTag: { projectId: number; tag: Omit<Tag, 'id'> }
createTag: {
projectId: number
tag: Omit<Tag, 'id' | 'project' | 'type' | 'is_system_tag' | 'is_permanent'>
}
getSegment: { projectId: number; id: number }
updateAccount: Account
deleteAccount: {
Expand Down
2 changes: 1 addition & 1 deletion frontend/web/components/base/grid/Column.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ Column.propTypes = {
value: OptionalNumber,
}

module.exports = Column
export default Column
2 changes: 1 addition & 1 deletion frontend/web/components/base/grid/Flex.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ Flex.propTypes = {
value: OptionalNumber,
}

module.exports = Flex
export default Flex
2 changes: 0 additions & 2 deletions frontend/web/components/feature-summary/FeatureRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,6 @@ const FeatureRow: FC<FeatureRowProps> = (props) => {
? {
environmentFlag,
environmentId,
flagId: environmentFlag?.id,
history,
noPermissions: !permission,
projectFlag,
Expand All @@ -216,7 +215,6 @@ const FeatureRow: FC<FeatureRowProps> = (props) => {
: {
environmentFlag,
environmentId,
flagId: environmentFlag?.id,
hasUnhealthyEvents:
isFeatureHealthEnabled && !!featureUnhealthyEvents?.length,
hideTagsByType: ['UNHEALTHY'],
Expand Down
5 changes: 4 additions & 1 deletion frontend/web/components/modals/AuditLogWebhooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ type AuditLogWebhooksType = {

const AuditLogWebhooks: FC<AuditLogWebhooksType> = ({ organisationId }) => {
const { data: webhooks, isLoading: webhooksLoading } =
useGetAuditLogWebhooksQuery({ organisationId }, { skip: !organisationId })
useGetAuditLogWebhooksQuery(
{ organisationId: parseInt(organisationId) },
{ skip: !organisationId },
)
const createWebhook = () => {
openModal(
'New Webhook',
Expand Down
10 changes: 5 additions & 5 deletions frontend/web/components/modals/create-experiment/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ import { saveFeatureWithValidation } from 'components/saveFeatureWithValidation'
import { FlagValueFooter } from 'components/modals/FlagValueFooter'
import { getChangeRequests } from 'common/services/useChangeRequest'
import ProjectProvider from 'common/providers/ProjectProvider'
import CreateFeature from 'components/modals/create-feature/tabs/CreateFeature'
import FeatureValueTab from 'components/modals/create-feature/tabs/FeatureValue'
import FeatureLimitAlert from 'components/modals/create-feature/FeatureLimitAlert'
import FeatureUpdateSummary from 'components/modals/create-feature/FeatureUpdateSummary'
import FeatureNameInput from 'components/modals/create-feature/FeatureNameInput'
import CreateFeature from 'components/modals/create-feature/tabs/CreateFeatureTab'
import FeatureValueTab from 'components/modals/create-feature/tabs/FeatureValueTab'
import FeatureLimitAlert from 'components/modals/create-feature/components/FeatureLimitAlert'
import FeatureUpdateSummary from 'components/modals/create-feature/components/FeatureUpdateSummary'
import FeatureNameInput from 'components/modals/create-feature/components/FeatureNameInput'
import ExperimentResultsTab from './ExperimentResultsTab'
import moment from 'moment'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ const FeatureLimitAlert: FC<FeatureLimitAlertType> = ({
onChange,
projectId,
}) => {
const { data: project } = useGetProjectQuery({ id: `${projectId}` })
const { data: project } = useGetProjectQuery({
id: typeof projectId === 'string' ? parseInt(projectId, 10) : projectId,
})

const featureLimitAlert = Utils.calculateRemainingLimitsPercentage(
project?.total_features,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type FeatureNameInputProps = {
value: string
onChange: (name: string) => void
caseSensitive: boolean
regex?: string
regex?: string | null
regexValid: boolean
autoFocus?: boolean
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React, { FC } from 'react'
import Utils from 'common/utils/utils'
import Button from 'components/base/forms/Button'
import { EnvironmentPermission } from 'common/types/permissions.types'

type IdentitySaveFooterProps = {
identityName?: string
environmentName: string
savePermission: boolean
isSaving: boolean
projectFlagName: string
invalid: boolean | number
onSave: () => void
}

const IdentitySaveFooter: FC<IdentitySaveFooterProps> = ({
environmentName,
identityName,
invalid,
isSaving,
onSave,
projectFlagName,
savePermission,
}) => {
return (
<div className='pr-3'>
<div className='mb-3 mt-4'>
<p className='text-left ml-3 modal-caption fs-small lh-small'>
This will update the feature value for the user{' '}
<strong>{identityName}</strong> in
<strong> {environmentName}.</strong>
{' Any segment overrides for this feature will now be ignored.'}
</p>
</div>

<div className='text-right mb-2'>
{Utils.renderWithPermission(
savePermission,
EnvironmentPermission.UPDATE_FEATURE_STATE,
<div>
<Button
onClick={onSave}
data-test='update-feature-btn'
id='update-feature-btn'
disabled={
!savePermission || isSaving || !projectFlagName || !!invalid
}
>
{isSaving ? 'Updating' : 'Update Feature'}
</Button>
</div>,
)}
</div>
</div>
)
}

export default IdentitySaveFooter
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import React, { Component } from 'react'
import FeatureListStore from 'common/stores/feature-list-store'
import ES6Component from 'common/ES6Component'
import { setModalTitle } from 'components/modals/base/ModalDefault'

// TODO: Migrate to a custom hook once we move away from Flux stores.
// This class component is necessary because it uses ES6Component/listenTo
// to subscribe to FeatureListStore events, which requires class lifecycle methods.
export default function withFeatureProvider(
WrappedComponent: React.ComponentType<any>,
) {
class FeatureProvider extends Component<any, any> {
constructor(props: any) {
super(props)
this.state = {
...props,
}
ES6Component(this)
}

componentDidMount() {
ES6Component(this)
this.listenTo(
FeatureListStore,
'saved',
({
changeRequest,
createdFlag,
error,
isCreate,
updatedChangeRequest,
}: any = {}) => {
if (error?.data?.metadata) {
error.data.metadata?.forEach((m: any) => {
if (Object.keys(m).length > 0) {
toast(m.non_field_errors[0], 'danger')
}
})
} else if (error?.data) {
toast('Error updating the Flag', 'danger')
return
} else {
const isEditingChangeRequest =
this.props.changeRequest && changeRequest
const operation = createdFlag || isCreate ? 'Created' : 'Updated'
const type = changeRequest ? 'Change Request' : 'Feature'

const toastText = isEditingChangeRequest
? `Updated ${type}`
: `${operation} ${type}`
const toastAction = changeRequest
? {
buttonText: 'Open',
onClick: () => {
closeModal()
this.props.history.push(
`/project/${this.props.projectId}/environment/${this.props.environmentId}/change-requests/${updatedChangeRequest?.id}`,
)
},
}
: undefined

toast(toastText, 'success', undefined, toastAction)
}
const envFlags = FeatureListStore.getEnvironmentFlags()

if (createdFlag) {
const projectFlag = FeatureListStore.getProjectFlags()?.find?.(
(flag: any) => flag.name === createdFlag,
)
window.history.replaceState(
{},
`${document.location.pathname}?feature=${projectFlag.id}`,
)
const newEnvironmentFlag = envFlags?.[projectFlag.id] || {}
setModalTitle(`Edit Feature ${projectFlag.name}`)
this.setState({
environmentFlag: {
...this.state.environmentFlag,
...(newEnvironmentFlag || {}),
},
projectFlag,
segmentsChanged: false,
settingsChanged: false,
valueChanged: false,
})
} else if (this.props.projectFlag) {
const newEnvironmentFlag =
envFlags?.[this.props.projectFlag.id] || {}
const newProjectFlag = FeatureListStore.getProjectFlags()?.find?.(
(flag: any) => flag.id === this.props.projectFlag.id,
)
this.setState({
environmentFlag: {
...this.state.environmentFlag,
...(newEnvironmentFlag || {}),
},
projectFlag: newProjectFlag,
segmentsChanged: false,
settingsChanged: false,
valueChanged: false,
})
}
},
)
}

listenTo: any

render() {
return (
<WrappedComponent
key={this.state.projectFlag?.id || 'new'}
{...this.state}
/>
)
}
}

return FeatureProvider
}
Loading
Loading