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

Tagging frontend #7418

Closed
wants to merge 10 commits into from
Closed

Tagging frontend #7418

wants to merge 10 commits into from

Conversation

betodealmeida
Copy link
Member

@betodealmeida betodealmeida commented Apr 30, 2019

CATEGORY

Choose one

  • Bug Fix
  • Enhancement (new features, refinement)
  • Refactor
  • Add tests
  • Build / Development Environment
  • Documentation

SUMMARY

This PR introduces the frontend for tags, behind a feature flag:

DEFAULT_FEATURE_FLAGS = {                                                                                              │
    'TAGGING_SYSTEM': True,                                                                                            │
}

When the feature is enabled, owners can tag charts:

tag_charts

And dashboards:

tag_dash

Note that tags can be autocompleted.

A user who's not an owner will see non-editable tags:

Screen Shot 2019-05-22 at 2 32 41 PM

When clicking on a tag, the user is taken to a page with content that has that tag:

tag_link

TEST PLAN

Tested locally. We've also been using this at Lyft for months.

ADDITIONAL INFORMATION

  • Has associated issue:
  • Changes UI
  • Requires DB Migration.
  • Confirm DB Migration upgrade and downgrade tested.
  • Introduces new feature or API
  • Removes existing feature or API

REVIEWERS

@mistercrunch @williaster @khtruong

@codecov-io
Copy link

codecov-io commented May 1, 2019

Codecov Report

Merging #7418 into master will decrease coverage by 0.15%.
The diff coverage is 27.21%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #7418      +/-   ##
==========================================
- Coverage   65.08%   64.92%   -0.16%     
==========================================
  Files         429      434       +5     
  Lines       21002    21261     +259     
  Branches     2338     2365      +27     
==========================================
+ Hits        13669    13804     +135     
- Misses       7217     7334     +117     
- Partials      116      123       +7
Impacted Files Coverage Δ
superset/assets/src/welcome/App.jsx 0% <0%> (ø) ⬆️
superset/assets/src/components/ObjectTags.jsx 10.52% <10.52%> (ø)
superset/assets/src/utils/tags.js 100% <100%> (ø)
superset/assets/src/featureFlags.ts 88.88% <100%> (+1.38%) ⬆️
superset/assets/src/tags.js 11.76% <11.76%> (ø)
superset/assets/src/welcome/TagsTable.jsx 15.38% <15.38%> (ø)
superset/assets/src/welcome/Welcome.jsx 52.63% <41.93%> (-27.37%) ⬇️
...uperset/assets/src/dashboard/components/Header.jsx 44.34% <83.33%> (+2.14%) ⬆️
...sets/src/explore/components/ExploreChartHeader.jsx 56.81% <87.5%> (+6.81%) ⬆️
... and 5 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 46579b1...ae40ee6. Read the comment docs.

@betodealmeida betodealmeida changed the title [WIP] Tagging frontend Tagging frontend May 22, 2019
@betodealmeida betodealmeida added enhancement:request Enhancement request submitted by anyone from the community .js lyft Related to Lyft labels May 22, 2019
@1AB9502
Copy link

1AB9502 commented Jun 17, 2019

@betodealmeida ,

Any plans on getting this merged?

@betodealmeida
Copy link
Member Author

@1AB9502 sorry for the delay with this. I need to add some integration tests. Let me put this up for review in the meantime.

@betodealmeida
Copy link
Member Author

cc: @khtruong

* specific language governing permissions and limitations
* under the License.
*/
/**
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's add a quick comment of what this div element is.

@1AB9502
Copy link

1AB9502 commented Jun 17, 2019

@betodealmeida

No worries! We are just really looking forward to getting this feature!

@@ -0,0 +1,213 @@
/**
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it necessary to be a less file? From quick skimming, a *.css extension should be enough.

QUERY: 'query',
});

export function fetchTags({ objectType, objectId, includeTypes = false }, callback, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Prefer returning Promise over callback. SupersetClient.get() already returns Promise which can be chained.

renderTable(type) {
const data = this.state.objects[type].map(o => ({
[type]: <a href={o.url}>{o.name}</a>,
creator: unsafe(o.creator),
Copy link
Contributor

Choose a reason for hiding this comment

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

What does unsafe do?

{ key: 'creator', label: 'Creator' },
{ key: 'modified', label: 'Modified' },
]}
defaultSort={{ column: 'modified', direction: 'desc' }}
Copy link
Contributor

Choose a reason for hiding this comment

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

create const outside class to avoid creating new object every time.

constructor(props) {
super(props);

this.fetchTags = fetchTags.bind(this, {
Copy link
Contributor

Choose a reason for hiding this comment

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

same parameter with addTag()


this.fetchTags = fetchTags.bind(this, {
objectType: OBJECT_TYPES.CHART,
objectId: props.chart.id,
Copy link
Contributor

Choose a reason for hiding this comment

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

What if the props and chart change? This id will not be updated.

return (
<div className="react-tags-rw">
{this.state.tags.map(tag => (
<Label bsStyle="info">
Copy link
Contributor

Choose a reason for hiding this comment

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

missing key

}

renderEditableTags() {
const Tag = props => (
Copy link
Contributor

Choose a reason for hiding this comment

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

This component should be declared somewhere else instead of redeclaring everytime in this render function. Can also be its own file.

Copy link
Member

@etr2460 etr2460 left a comment

Choose a reason for hiding this comment

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

I might be missing context from when this was originally proposed, but I had some higher level questions here:

Is there a reason why you choose to create individual API functions instead of a set of redux actions to fetch and update tags? It makes sense to pull the tagging actions into its own file because it would be shared between both Explore and Dashboard views, but I think that maintaining the state of tags in its own redux store would be more typical and follow the patterns i've seen throughout superset already.

I would recommend creating a new directory in assets/src/tags to keep the component files, the main tags page, the redux actions and the reducers and then wire up the required state to both explore and dashboard components. It would make tagging consistent with the rest of the app, clearer, and easier to maintain

@@ -0,0 +1,16 @@
{
Copy link
Member

Choose a reason for hiding this comment

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

Should this file be here?

Copy link
Member Author

Choose a reason for hiding this comment

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

My mistake, let me remove it.

const defaultTab = isFeatureEnabled(FeatureFlag.TAGGING_SYSTEM)
? 'tags'
: 'favorites';
const parsedUrl = new URI(window.location);
Copy link
Member

Choose a reason for hiding this comment

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

This seems odd that we're adding the tags page as a subpage of welcome. Why not create a new page at /superset/tags?

Copy link
Member

Choose a reason for hiding this comment

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

Also, if all of this is only required for the TAGGING_SYSTEM feature flag, then can't we wrap all the logic in that flag? Right now even if you turn off the feature flag, all this code is executed, which seems to remove the safety that feature flags provide

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point. I added the feature flag later (since we've been using this for a while), will improve the wrapped logic.

updateURL(key, value) {
const parsedUrl = new URI(window.location);
parsedUrl.search(data => ({ ...data, [key]: value }));
window.history.pushState({ value }, value, parsedUrl.href());
Copy link
Member

Choose a reason for hiding this comment

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

manually adjusting the window's history is really error prone... i'm worried that there are a bunch of edge cases here

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah. If we opt to do this (I saw your comment below) I can write comprehensive unit tests.

}
handleSelect(key) {
// store selected tab in URL
window.history.pushState({ tab: key }, key, `#${key}`);
Copy link
Member

Choose a reason for hiding this comment

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

Using the URL to maintain application state seems like an antipattern. Why not use the redux store?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is so we can deep link to a particular tag search when the user clicks a tag (though this could be done encoding the info on the path), and also so that the user can share search results for a tag.

@betodealmeida
Copy link
Member Author

@etr2460

Is there a reason why you choose to create individual API functions instead of a set of redux actions to fetch and update tags? It makes sense to pull the tagging actions into its own file because it would be shared between both Explore and Dashboard views, but I think that maintaining the state of tags in its own redux store would be more typical and follow the patterns i've seen throughout superset already.

Great question. Yeah, we've been running this code at Lyft for maybe a year now, so it's definitely outdated and would be written differently from scratch today.

IIRC we went with API functions since the state lives outside the applications (explore, dashboards, SQL Lab). Maybe @mistercrunch remembers better?

I would recommend creating a new directory in assets/src/tags to keep the component files, the main tags page, the redux actions and the reducers and then wire up the required state to both explore and dashboard components. It would make tagging consistent with the rest of the app, clearer, and easier to maintain.

+1

@stale
Copy link

stale bot commented Aug 18, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. For admin, please label this issue .pinned to prevent stale bot from closing the issue.

@stale stale bot added the inactive Inactive for >= 30 days label Aug 18, 2019
@mistercrunch mistercrunch added the .pinned Draws attention label Aug 19, 2019
@stale stale bot removed the inactive Inactive for >= 30 days label Aug 19, 2019
@senduren
Copy link

Looks like this PR has gone stale, any idea on what version we can expect this feature?

@mrshu
Copy link
Contributor

mrshu commented Jan 7, 2020

Echoing @senduren's comment above, it has been about half a year since the last commit in this PR. Based on @betodealmeida's last comment, does it look like a full rewrite will be necessary? Is it this feature still on the roadmap for future versions of Superset?

Thanks a lot!

@1AB9502
Copy link

1AB9502 commented Jan 7, 2020

Chiming in as well. Our users love this feature. During the latest upgrade we had to add everything back manually. Would love to see this feature merged!

@mfyuce
Copy link

mfyuce commented May 10, 2020

Hi All,

First thanks for the nice feature implementation.

I have synced the source files for this PR with the latest master branch on incubator-superset and sent a PR to lyft/incubator-superset fork (lyft#98). If it is accepted we can continue with that.

Or, I can also send another PR to incubator-superset if it is requested.

We think the functionality is really nice to have.

All the best,

Copy link

@kalimuthu123 kalimuthu123 left a comment

Choose a reason for hiding this comment

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

but tagging (grouping) the dashboard is a good feature but the expection was is it saved in backend Db

@mfyuce
Copy link

mfyuce commented Jul 2, 2020

in this PR, and the one send to lyft/incubator-superset fork (lyft#98), it is being saved to db.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement:request Enhancement request submitted by anyone from the community lyft Related to Lyft .pinned Draws attention size/XL
Projects
None yet
Development

Successfully merging this pull request may close these issues.