Adds an example date as a detail of the locale picker, so that the user
can see what effect their chosen locale would have on date formatting:
<img width="436" height="157" alt="image"
src="https://github.com/user-attachments/assets/d5757380-3cda-4857-99d7-bac8866d31f5"
/>
The example wraps on smaller screens:
<img width="291" height="207" alt="image"
src="https://github.com/user-attachments/assets/e3ef1678-6846-4027-b563-253195e2de99"
/>
The example date is the **date and time of the very first commit in the
Unleash repo**. By some stroke of luck, it happens to have everything
we're looking for:
- A date that is more than the 12th (to clearly differentiate between
days and months)
- A month that is less than 10 (to show whether leading zeroes are shown
or not)
- An hour that is more than 11 to show whether it's a 24-hour clock or
an AM/PM system
The date string is without a time zone offset because that means it'll
always be interpreted as local time for the user. MDN's [docs on Date
and what happens when you call it with a time
string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#date_time_string_format)
state that:
> When the time zone offset is absent, date-only forms are interpreted
as a UTC time and **date-time forms are interpreted as a local time**.
I've checked this by changing my locale. With the timezone offset, the
time changes based on my timezone, but without it, it always shows as
the expected value.
Updates a few remaining places where we check constraint operators with
the new constraint operator checks. Additionally, because there was only
one remaining place where we used the `oneOf` function, I replaced it
with a normal `includes` check and deleted the `oneOf` util. From what I
can tell, there's no need to have that utility function; it doesn't
provide much benefit over using the language built-ins 🤷🏼
This PR takes two steps towards better constraint handling:
## New type: `IConstraintWithId`
Introduces a new type, `IConstraintWithId`. This is the same as an
`IConstraint`, except the constraint id property is required. The idea
is that the list of editable constraints should move towards using this
instead of just `IConstraint`. That should prevent us (on a type-level)
from seeing more of the same kind of errors we saw with the segment
constraints yesterday.
I don't want to go ahead and update all the upstream uses of this to
IConstraintWithId in this PR, so I'll look at that separately.
## API payload constraint replacer
Introduces an api payload constraint "replacer", which we can use for
[JSON.stringify's `replacer`
parameter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#the_replacer_parameter).
The current implementation works both for strategies and for segments
and has been added to edit + create forms for both of these resources.
This has a couple benefits:
1. We can clearly state exactly how we want them to be rendered,
including property order. I've decided to go with context -> operator ->
value(s) as the main one (check the screenie), as I believe this is the
most logical reading order.
2. We can exclude value/values (whichever one doesn't work with the
operator)
3. It doesn't matter how we treat constraints internally, we can still
present the payload how we want
4. Importantly: this only affects the stringification for the
user-facing API payload, so it's very low risk. It does not affect
anything that we actually send to the api.
Here's what it can look like with ordered properties:
<img width="392" alt="image"
src="https://github.com/user-attachments/assets/f46f77c8-0b5a-4ded-b13a-bb567df60bd3"
/>
This PR addresses and removes the last comment related to the
addEditStrategy flag. In doing so, I have also removed the remaining
dangling files from the new constraint accordion directory. I believe
that everything that's left in there now is currently in use.
This PR continues the cleanup after removing the addEditStrategy flag
(part 2 of ???). The primary purpose of this PR is to delete and remove
all references to the LegacyConstraintAccordion.
I've gone and updated all references to the legacy files in external
components and verified manually that they still work.
Most of the files in this PR are changing references. I've extracted two
bits into more general constants/utils:
1. Constraint IDs are a symbol. it was exported as a const from the
previous createEmptyConstraint file. I've moved it into constants.
2. formatOperatorDescription was similarly used all over the place, so
I've placed it in the shared utils directory.
In reviewing this, you can ignore any changes in the legacy constraint
accordion folder, because that's all been deleted. Instead, focus on the
changes in the other files. It's primarily just import updates, but
would be good to get a second set of eyes, anyway.
On insights and project status, we would like to show "technica debt"
instead of "health". New value is that of `1/health`, or simplified:
`healthy flags / total flags`
This removes a strategy that was already deprecated, but only for new
installations.
I tested starting with an installation with this strategy being used and
then updating, and I was still able to edit the strategy, so this should
not impact current users.
On a fresh install the strategy is no longer available.
---------
Co-authored-by: Nuno Góis <github@nunogois.com>
We're migrating to ESM, which will allow us to import the latest
versions of our dependencies.
Co-Authored-By: Christopher Kolstad <chriswk@getunleash.io>
Fixes a number of issues that would surface in UTC-n (where n > 1)
timezones. I've not found a way to check this with tests (and it looks
like [we weren't able to last time
either](https://github.com/Unleash/unleash/pull/9110/files#r1919746328)),
so all the testing's been done manually by adjusting my system time and
zone. (From what I understand, you can't generate a Date with a specific
TZ offset in JS: it's only utc or local time)
Resolved:
- [x] Selecting "Jan" in the dropdown results in the selection being
"December" (off by one in the selector)
- [x] Selecting a month view only gives you one data point (and it's
probably empty). Wrong date parsing on the way out resulted in sending
`{ from: "2025-02-28", to: "2025-02-28"}` instead of `{ from:
"2025-03-01", to: "2025-03-31"}`
- [x] The dates we create when making "daysRec" need to be adjusted.
They showed the wrong month, so the dates were off.
- [x] Make sure the labels are correct when hovering over. Again: we
used the wrong month for generating these.
- [x] The available months are wrong. Incorrect month parsing again.
- [x] The request summary month is wrong. You guessed it: incorrect
month parsing
Makes the data returned from the traffic search a union type to avoid
nasty object-is-undefined errors at runtime.
It requires more explicit handling, sure, but it means we don't need
to accept undefined.
Adds new monthly estimation functions that operate on raw usage data
instead of chart data. This brings those methods in line with the rest
of the traffic calculation functions that we have in that file and means
we can remove other external dependencies.
This is somewhat inspired by #9218, but not directly linked.
Implements a function that cleans and filters incoming data from the
new traffic API.
Specifically, it:
- Removes `/edge` data points
- Removes any data from before may 2024, which is the first full month
we have on record
Because all uses of the existing hook do this filtering themselves, I
have added the filtering at the hook level. This is to avoid
forgetting this filtering later. If we find out we need this data, we
can move the filtering.
This PR refactors the `NetworkTrafficUsage.tsx` and `useTrafficData`
files a bit.
The primary objective was to make the network traffic usage component
easier to work with, so I suggest to the reviewer that they start there.
Part of that refactoring, was taking things out of the useTraffic hook
that didn't need to be there. In the end, I'd removed so much that I
didn't even need the hook itself in the new component, so I switched
that to a regular useState.
It made more sense to me to put some of the functions inside the hook
into a separate file and import them directly (because they don't rely
on any hook state), so I have done that and removed those functions from
the trafficData hook. In this case, I also moved the tests.
I have not added any new tests in this PR, but will do so in a
follow-up. The functions I intend to test have been marked as such.
Follow-up to: https://github.com/Unleash/unleash/pull/8642
Introduces a reusable `Highlight` component that leverages the Context
API pattern, enabling highlight effects to be triggered from anywhere in
the application.
This update refactors the existing highlight effect in the event
timeline to use the new Highlight component and extends the
functionality to include the Unleash AI experiment, triggered by its
entry in the "New in Unleash" section.
After we implemented new feature flag creation flow, this are not used
anymore.
Creation is now handled by **CreateFeatureDialog**.
Also edit component can be minified, because it does not need so many
fields anymore.
**Upgrade to React v18 for Unleash v6. Here's why I think it's a good
time to do it:**
- Command Bar project: We've begun work on the command bar project, and
there's a fantastic library we want to use. However, it requires React
v18 support.
- Straightforward Upgrade: I took a look at the upgrade guide
https://react.dev/blog/2022/03/08/react-18-upgrade-guide and it seems
fairly straightforward. In fact, I was able to get React v18 running
with minimal changes in just 10 minutes!
- Dropping IE Support: React v18 no longer supports Internet Explorer
(IE), which is no longer supported by Microsoft as of June 15, 2022.
Upgrading to v18 in v6 would be a good way to align with this change.
TS updates:
* FC children has to be explicit:
https://stackoverflow.com/questions/71788254/react-18-typescript-children-fc
* forcing version 18 types in resolutions:
https://sentry.io/answers/type-is-not-assignable-to-type-reactnode/
Test updates:
* fixing SWR issue that we have always had but it manifests more in new
React (https://github.com/vercel/swr/issues/2373)
---------
Co-authored-by: kwasniew <kwasniewski.mateusz@gmail.com>
This PR adds a 'change-request-conflict-created' event whenever someone
save a strategy update for a strategy that's used in either pending or
scheduled change requests.
Data for pending change requests will only be sent if change requests
are enabled. Data for scheduled change requests will be sent regardless.
Getting this data is somewhat involved, so I've extracted as much of the
logic into a separate file as possible.
The event re-uses the existing `change_request` metric and sends the
following data for each change request that we discover conflicts on:
```ts
{
state: ChangeRequestState,
changeRequest: string, // <unleash identifier>#<change request id>
action: 'edit-strategy',
eventType: 'conflict-created'
}
```
There's only one action for this for now, but we could expand this event
to things such as strategy deletion, feature archival, in the future.
That said, I'd be happy to take it out.
## Discussion points
### Has the strategy actually been updated?
This does not check whether a strategy has actually changed before
emitting the event, only that you save your strategy changes.
This assumes that most people will simply close the modal by
clicking/tapping outside it or using the escape key instead of pressing
save.
However, it will likely lead to some false positives. If we think that
is an issue, I would suggest adding a check that something in the
strategy has actually changed in a follow-up PR.
Added conflict count to CR metrics and CR id.
Something to think about:
There was idea that we can aggregate this data based on CR id, but CR id
is just a number from 0 to x. So it will not be unique across instances.
---------
Co-authored-by: Thomas Heartman <thomas@getunleash.io>
Lots of work here, mostly because I didn't want to turn off the
`noImplicitAnyLet` lint. This PR tries its best to type all the untyped
lets biome complained about (Don't ask me how many hours that took or
how many lints that was >200...), which in the future will force test
authors to actually type their global variables setup in `beforeAll`.
---------
Co-authored-by: Gastón Fournier <gaston@getunleash.io>