Skip to content

Commit

Permalink
Closes #764 autodetect site urls (#815)
Browse files Browse the repository at this point in the history
* Closes #764 autodetect site urls

* Add EditAppUrls

* Refactor imports

* Fix nits
  • Loading branch information
timgl committed May 22, 2020
1 parent 8480856 commit 5426c87
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 309 deletions.
23 changes: 15 additions & 8 deletions frontend/src/lib/components/AppEditorLink/AppEditorLink.js
@@ -1,9 +1,10 @@
import React, { useState } from 'react'
import { useValues } from 'kea'

import { ChooseURLModal } from './ChooseURLModal'
import { EditAppUrls } from './EditAppUrls'
import { appEditorUrl } from './utils'
import { userLogic } from '../../../scenes/userLogic'
import { userLogic } from 'scenes/userLogic'
import { Modal, Button } from 'antd'

export function AppEditorLink({ actionId, style, className, children }) {
const [modalOpen, setModalOpen] = useState(false)
Expand All @@ -23,12 +24,18 @@ export function AppEditorLink({ actionId, style, className, children }) {
>
{children}
</a>
{modalOpen && (
<ChooseURLModal
actionId={actionId}
dismissModal={() => setModalOpen(false)}
/>
)}
<Modal
visible={modalOpen}
title={
actionId
? 'Choose the domain on which to edit this action'
: 'Choose the domain on which to create this action'
}
footer={<Button onClick={() => setModalOpen(false)}>Close</Button>}
onCancel={() => setModalOpen(false)}
>
<EditAppUrls actionId={actionId} allowNavigation={true} dismissModal={() => setModalOpen(false)} />
</Modal>
</>
)
}
134 changes: 0 additions & 134 deletions frontend/src/lib/components/AppEditorLink/ChooseURLModal.js

This file was deleted.

169 changes: 169 additions & 0 deletions frontend/src/lib/components/AppEditorLink/EditAppUrls.js
@@ -0,0 +1,169 @@
import React, { useState } from 'react'
import { kea, useActions, useValues } from 'kea'
import { Spin, Button, List } from 'antd'
import { PlusOutlined } from '@ant-design/icons'

import { userLogic } from 'scenes/userLogic'
import api from 'lib/api'
import { toParams } from 'lib/utils'
import { UrlRow } from './UrlRow'
import { toast } from 'react-toastify'

const defaultValue = 'https://'

const appUrlsLogic = kea({
actions: () => ({
addUrl: value => ({ value }),
removeUrl: index => ({ index }),
updateUrl: (index, value) => ({ index, value }),
}),

loaders: ({ values }) => ({
suggestions: {
loadSuggestions: async () => {
let params = {
events: [{ id: '$pageview', name: '$pageview', type: 'events' }],
breakdown: '$current_url',
}
let data = await api.get('api/action/trends/?' + toParams(params))
let domainsSeen = []
return data
.filter(item => {
let domain = new URL(item.breakdown_value).hostname
if (domainsSeen.indexOf(domain) > -1) return
if (values.appUrls.filter(url => url.indexOf(domain) > -1).length > 0) return
domainsSeen.push(domain)
return true
})
.map(item => item.breakdown_value)
.slice(0, 20)
},
},
}),

events: ({ actions }) => ({
afterMount: actions.loadSuggestions,
}),

defaults: () => ({
appUrls: state => userLogic.selectors.user(state).team.app_urls || [defaultValue],
}),

allURLs: ({ selectors }) => ({
recordsForSelectedMonth: [
() => [selectors.appUrls, selectors.suggestions],
(appUrls, suggestions) => {
return appUrls + suggestions
},
],
}),

reducers: ({ actions }) => ({
appUrls: [
[defaultValue],
{
[actions.addUrl]: (state, { value }) => state.concat([value || defaultValue]),
[actions.updateUrl]: (state, { index, value }) => Object.assign([...state], { [index]: value }),
[actions.removeUrl]: (state, { index }) => {
const newAppUrls = [...state]
newAppUrls.splice(index, 1)
return newAppUrls
},
},
],
suggestions: [
[],
{
[actions.addUrl]: (state, { value }) => [...state].filter(item => value !== item),
},
],
isSaved: [
false,
{
[actions.addUrl]: () => false,
[actions.removeUrl]: () => false,
[actions.updateUrl]: () => false,
[userLogic.actions.userUpdateSuccess]: (state, { updateKey }) => updateKey === 'SetupAppUrls' || state,
},
],
}),

listeners: ({ sharedListeners }) => ({
addUrl: sharedListeners.saveAppUrls,
removeUrl: sharedListeners.saveAppUrls,
updateUrl: sharedListeners.saveAppUrls,
}),

sharedListeners: ({ values }) => ({
saveAppUrls: () => {
toast('URLs saved', { toastId: 'EditAppUrls' })
userLogic.actions.userUpdateRequest({ team: { app_urls: values.appUrls } }, 'SetupAppUrls')
},
}),
})

export function EditAppUrls({ actionId, allowNavigation }) {
const { appUrls, suggestions, suggestionsLoading, isSaved } = useValues(appUrlsLogic)
const { addUrl, removeUrl, updateUrl } = useActions(appUrlsLogic)
const [loadMore, setLoadMore] = useState()

return (
<div>
<List bordered>
{appUrls.map((url, index) => (
<UrlRow
key={`${index},${url}`}
actionId={actionId}
allowNavigation={allowNavigation}
url={url}
saveUrl={value => updateUrl(index, value)}
deleteUrl={() => removeUrl(index)}
/>
))}
{appUrls.length === 0 && <List.Item>No url set yet.</List.Item>}
<List.Item>
Suggestions: {suggestionsLoading && <Spin />}{' '}
{!suggestionsLoading && suggestions.length === 0 && 'No suggestions found.'}
</List.Item>
{suggestions &&
suggestions.slice(0, loadMore ? suggestions.length : 5).map(url => (
<List.Item
key={url}
onClick={() => addUrl(url)}
style={{ cursor: 'pointer', justifyContent: 'space-between' }}
>
<a href={url} onClick={e => e.preventDefault()}>
{url}
</a>
<PlusOutlined style={{ color: 'var(--success)' }} />
</List.Item>
))}
{!loadMore && suggestions && suggestions.length > 5 && (
<div
style={{
textAlign: 'center',
margin: '12px 0',
height: 32,
lineHeight: '32px',
}}
>
<Button onClick={() => setLoadMore(true)}>Load more</Button>
</div>
)}
</List>

{isSaved && (
<span className="text-success float-right" style={{ marginLeft: 10 }}>
URLs saved.
</span>
)}
<Button
type="link"
onClick={() => addUrl()}
style={{ padding: '5px 0', margin: '5px 0', textDecoration: 'none' }}
>
+ Add Another URL
</Button>
</div>
)
}

0 comments on commit 5426c87

Please sign in to comment.