Skip to content
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

Add ConfigEditor util components #4

Merged
merged 5 commits into from
Nov 15, 2021
Merged

Add ConfigEditor util components #4

merged 5 commits into from
Nov 15, 2021

Conversation

andresmgot
Copy link
Collaborator

@andresmgot andresmgot commented Nov 10, 2021

Ref: #28

In #28 I suggest to create a generic ConfigEditor component to use in the different data sources. After a first revision, I don't think that's the best path forward, it forces to create some strict structure of the configuration that may be difficult to update and understand.

Rather than exposing a ConfigEditor, I have created two wrapper components around the ResourceSelector and the Input components to adapt them to the ConfigEditor requirements.

@andresmgot andresmgot changed the title Add ConfigEditor Component Add SQLConfigEditor Component Nov 10, 2021
Copy link
Contributor

@sunker sunker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great stuff!

rollup.config.ts Outdated
@@ -26,7 +26,7 @@ const buildCjsPackage = ({ env }) => {
},
},
],
external: ['react', '@grafana/data', '@grafana/ui', 'lodash'],
external: ['react', '@grafana/data', '@grafana/ui', 'lodash', '@grafana/runtime'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid adding this dep?

The ConnectionConfig in this package is currently used in the DataSourceHttpSettings.tsx component in Grafana UI. This is because any data source that uses http for data source auth can theoretically use AWS SIGV4 to authenticate, given grafana is running on an EC2 instance or in AMG. This means grafana/ui depends on the grafana/aws-sdk. grafana/ui cannot, or at least should not, depend on grafana/runtime. I think in theory, this should be fine because it's only the ConnectionConfig that is used inside grafana/ui, but I seem to recall that all dependencies from the aws-sdk are being pulled into the grafana/ui build, and in that case this won't work. Might be because tree shaking is not setup correctly in the grafana ui package bundle, don't know.

Beside from the above mentioned problem, I also think it's better that the components that we expose in this package don't depend on the runtime. It should be up to the plugin to specify it's dependency to grafana. So it's better to just pass the getBackendSrv func as a prop to the config editor.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have never found that 😅 thanks for the insight!

if (elem.type) {
return elem;
}
if ('fetch' in i) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a ts guard here so you don't have to cast it with as

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right, using the in operator, it's not needed to use as.

return <Selector key={i.id} {...props} input={i as SelectorInput} saveOptions={saveOptions} />;
} else {
// The input is a text field
const input = i as TextInput;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here too

src/sql/ResourceSelector.tsx Show resolved Hide resolved
Copy link
Member

@sarahzinger sarahzinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me! I had a few random thoughts as I read that I shared, but I don't think of any of them as blocking just things that occurred to me while reading

import { ConnectionConfig } from 'ConnectionConfig';

type SQLDataSourceJsonData<T extends AwsAuthDataSourceJsonData> = T & {
[n: string]: any;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

random and unimportant but you could use Record here if you prefer

<Input
data-testid={input['data-testid']}
className="width-30"
value={input.value || props.options.jsonData[input.id] || ''}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what would you think about choosing either input.value or props.options.jsonData[input.id] rather than doing one or the other?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not super happy with this either. I needed both, this is for the case in which props.options.jsonData[input.id] is an object, for example. In that case, the user needs to set value: props.options.jsonData[input.id].foo but I didn't want to force all the callers to set the value if 95% of the cases it will be value: props.options.jsonData[input.id]. I am following that pattern in other places like the onChange above in line 33.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

at the end I replaced the id property with a full path of the jsonData property. That solves this issue and avoid having to define a value and jsonData.


export interface SQLConfigEditorProps
extends DataSourcePluginOptionsEditorProps<SQLDataSourceJsonData<{}>, AwsAuthDataSourceSecureJsonData> {
inputs: Array<SelectorInput | TextInput | JSX.Element>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it would be simpler to use props.children and always pass existing props and saveOptions to those children and let the consumer of SQLConfigEditor have control over what goes inside it and whether or not it uses saveOptions. Might make it more flexible for the future as well? But maybe too flexible? Idk. Just sharing a thought in case it's helpful

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right, I am not super fond of this solution. The thing is that I wanted to avoid the burden of having to generate a full ResourceSelector for the data sources, just setting a subset of properties but it's true that this array may not be the best. I will try to create a wrapper component and just use those as children 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the end I created a wrapper around the ResourceSelector applied to the configuration view and remove the ConfigEditor component. Now the caller needs to define the function saveOptions (and that will be duplicated) but it feels cleaner than this array.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool seems sensible to me! If you find yourself not wanting saveOptions duplicated this package could export a hook useSaveOptions or something like that but also it makes sense to me that the individual packages would have that logic.

@andresmgot andresmgot changed the title Add SQLConfigEditor Component Add ConfigEditor util components Nov 11, 2021
Copy link
Member

@sarahzinger sarahzinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the changes you made! I think it would be cool to have documentation somewhere of how to use these utils to make a ConfigEditor or something but that could happen in another pr maybe, perhaps when they are used we could just link to it being used somewhere

Copy link
Contributor

@sunker sunker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Just a nit

Yeah would be nice to see how this is used. Can you put up a draft PR for how redshift or athena use these components?

jsonDataPath: 'foo',
};

describe('InlineText', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InlineInput

fetch: () => Promise<Array<string | SelectableValue<string>>>;
dependencies?: string[];
label?: string;
'data-testid'?: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need the test id? Wouldn't using getByLabelTest suffice?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't, it's an issue with grafana/ui (I guess I should create an issue for this?). You get this error using getByLabelText:

    TestingLibraryElementError: Found a label with the text of: <>, however no form control was found associated to that label. Make sure you're using the "for" attribute or "aria-labelledby" attribute correctly.

Also, the test-id is used in the e2e test (the flows only work with aria-labels and test-ids)

@andresmgot
Copy link
Collaborator Author

andresmgot commented Nov 15, 2021

Thanks @sunker @sarahzinger! For reference, I have pushed some drafts for you to take a look to more complex examples (apart from the tests):

ConfigEditor

ConfigEditor

@andresmgot andresmgot merged commit 0e03616 into main Nov 15, 2021
@andresmgot andresmgot deleted the configEditor branch November 15, 2021 10:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants