-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Simpler default file names #453
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Self-review
@@ -13,11 +11,7 @@ export function useCreateGenerator() { | |||
|
|||
const createTestGenerator = useCallback(async () => { | |||
try { | |||
const newGenerator = createNewGeneratorFile() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to do it in the render process
src/main.ts
Outdated
@@ -962,3 +985,35 @@ const cleanUpProxies = async () => { | |||
kill(proc.pid) | |||
}) | |||
} | |||
|
|||
const generateUniqueFileName = async ({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be in a util file, but I'd need to create a new one, since utils/file.ts
has some exports that are used in render
:/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is where having the app split up based on it's entry point would be handy:
shared/
- utils/
- file.ts
main/
- index.ts
render/
- utils/
- file.ts
- index.ts
This would allows us to setup a no-restricted-imports
rule in ESLint so that things in render/
can't import from main/
and vice versa.
@@ -5,7 +5,7 @@ export function createEmptyRule(type: TestRule['type']): TestRule { | |||
case 'correlation': | |||
return { | |||
type: 'correlation', | |||
id: self.crypto.randomUUID(), | |||
id: crypto.randomUUID(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: although it's not a big deal, should we stop storing rule ids in the generator file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now, I believe it's only used by the state manager (so we know each one is selected/being edited etc). It might be easier to have an id on file than setting than during runtime 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should store them because:
- They are convenient when writing the frontend, e.g. for
key
props. - If you diff two files, you can tell whether it was one thing being changed or one thing being removed and another added.
- JavaScript in general has no concept of value equality when it comes to complex types, so being able to easily check for equality via an
id
is very handy.
Like @cristianoventura said, setting them during runtime is harder.
You'd have to traverse the entire hierarchy of objects and slap and id on the things you care about, and if you load the thing from disk again you'll get an entirely new object with new id:s.
For instance, consider checking if a file has unsaved changes. If the id:s aren't stored, we would have to strip all the ids from everything before doing any comparison.
That said, could we switch to nanoid
? No need to use crypto-grade randomness and nanoid
s are a bit terser than UUIDs. 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That said, could we switch to nanoid? No need to use crypto-grade randomness and nanoids are a bit terser than UUIDs. 😅
We could, but what would be the benefits of this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could, but what would be the benefits of this?
None, really. A bit more efficient (crypto is computationally expensive), saves a few bytes of space and IMO they are easier to read than UUIDs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the last argument is the strongest one, but these ids aren't user-facing so I wouldn't make it a priority.
As for performance, in the benchmarks I found crypto.randomUUID()
had much higher number of operations per second than nanoid()
, but it probably doesn't make any measurable difference in the context of k6 studio
const generatorFile = await window.studio.generator.loadGenerator(fileName) | ||
return GeneratorFileDataSchema.parse(generatorFile.content) | ||
const generator = await window.studio.generator.loadGenerator(fileName) | ||
return GeneratorFileDataSchema.parse(generator) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO this should be happening in main
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll open a separate PR for this change
JSON.stringify(har, null, 4), | ||
prefix | ||
) | ||
const prefix = getHostNameFromURL(startUrl) ?? 'Recording' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's another change: if no starting URL is provided, the name will follow the Recording - YYYY-MM-DD
pattern
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It works as expected! 🚀
I left a comment for clarification before approving.
src/main.ts
Outdated
let fileExists = await access(path.join(directory, uniqueFileName)) | ||
.then(() => true) | ||
.catch(() => false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason why we shouldn't use fs.existsSync
here instead? It'd look semantically more appropriate as it returns a boolean value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using async fs functions follows the electron performance recommendations and fs.access
is the recommended replacement of the deprecated async fs.exists
.
Interestingly, there's the following statement about fs.exists
:
Using fs.exists() to check for the existence of a file before calling fs.open(), fs.readFile(), or fs.writeFile() is not recommended. Doing so introduces a race condition, since other processes may change the file's state between the two calls. Instead, user code should open/read/write the file directly and handle the error raised if the file does not exist.
Perhaps, the pattern itself is wrong, and even access
shouldn't be used here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what you want to do is use await fs.writeFile(path, data, { flag: 'ax+' })
(see flags) and repeat that with a new suffix until the write succeeds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO it's okay to use these methods in certain places (like a one-off operation, during initialization) that don't compromise the event loop.
@allansson's suggestion seems to handle both the check and the write at the same time so we can consider that approach as well.
If using fs.access
, we could condering cleaning up the then/catch block if we move it to a helper function since it's been used in a few places.
const fileExists = await checkFileExsits(path.join(directory, uniqueFileName)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I rewrote the function to use writeFile
@@ -5,7 +5,7 @@ export function createEmptyRule(type: TestRule['type']): TestRule { | |||
case 'correlation': | |||
return { | |||
type: 'correlation', | |||
id: self.crypto.randomUUID(), | |||
id: crypto.randomUUID(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now, I believe it's only used by the state manager (so we know each one is selected/being edited etc). It might be easier to have an id on file than setting than during runtime 🤔
@@ -41,7 +37,10 @@ export function useUpdateValueInGeneratorFile(fileName: string) { | |||
return useMutation({ | |||
mutationFn: async ({ key, value }: { key: string; value: unknown }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing to do with this PR really, but just an idea: instead of passing a key and value to update (which doesn't seem to be type safe?), why not use a map
function:
useUpdateInFile(fileName: (generator: Generator) => {
return {
...generator,
myValue: "hello"
}
})
src/main.ts
Outdated
let fileExists = await access(path.join(directory, uniqueFileName)) | ||
.then(() => true) | ||
.catch(() => false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO it's okay to use these methods in certain places (like a one-off operation, during initialization) that don't compromise the event loop.
@allansson's suggestion seems to handle both the check and the write at the same time so we can consider that approach as well.
If using fs.access
, we could condering cleaning up the then/catch block if we move it to a helper function since it's been used in a few places.
const fileExists = await checkFileExsits(path.join(directory, uniqueFileName)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! 🙌
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really like this change. Remove much of the clutter in the sidebar and it overall just feel more organized now.
Great job! 💯
Description
GeneratorFile
as it's become redundantHow to Test
Verify that the following works as before (apart from the new filenames):