2021-05-21 14:37:30 +00:00
|
|
|
import React, { useContext, useMemo, useState } from "react"
|
|
|
|
import Style from "./RepositoryViewer.module.css"
|
|
|
|
import ContextLanguage from "../../contexts/ContextLanguage"
|
|
|
|
import useBackendResource from "../../hooks/useBackendResource"
|
|
|
|
import useBackendViewset from "../../hooks/useBackendViewset"
|
|
|
|
import objectToWordcloudFormat from "../../utils/objectToWordcloudFormat"
|
|
|
|
import countTweetWords from "../../utils/countTweetWords"
|
|
|
|
import BoxHeader from "../base/BoxHeader"
|
|
|
|
import Loading from "../base/Loading"
|
|
|
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
2021-05-25 02:06:14 +00:00
|
|
|
import { faFolder, faFolderOpen, faPlus, faTrash } from "@fortawesome/free-solid-svg-icons"
|
2021-05-21 14:37:30 +00:00
|
|
|
import BoxRepositoryTweets from "../interactive/BoxRepositoryTweets"
|
|
|
|
import PickerVisualization from "../interactive/PickerVisualization"
|
|
|
|
import BoxVisualizationWordcloud from "../interactive/BoxVisualizationWordcloud"
|
|
|
|
import BoxVisualizationChart from "../interactive/BoxVisualizationChart"
|
|
|
|
import BoxVisualizationMap from "../interactive/BoxVisualizationMap"
|
|
|
|
import BoxVisualizationStats from "../interactive/BoxVisualizationStats"
|
|
|
|
import PickerFilter from "../interactive/PickerFilter"
|
|
|
|
import useArrayState from "../../hooks/useArrayState"
|
|
|
|
import BoxFilters from "../interactive/BoxFilters"
|
|
|
|
import ContextRepositoryViewer from "../../contexts/ContextRepositoryViewer"
|
2021-05-21 15:35:33 +00:00
|
|
|
import BoxFilterContains from "../interactive/BoxFilterContains"
|
|
|
|
import BoxFilterUser from "../interactive/BoxFilterUser"
|
|
|
|
import BoxFilterHashtag from "../interactive/BoxFilterHashtag"
|
2021-05-21 17:52:56 +00:00
|
|
|
import BoxFilterLocation from "../interactive/BoxFilterLocation"
|
2021-05-22 02:44:08 +00:00
|
|
|
import useMapAreaState from "../../hooks/useMapAreaState"
|
2021-05-21 17:52:56 +00:00
|
|
|
import BoxFilterDatetime from "../interactive/BoxFilterDatetime"
|
|
|
|
import BoxFilterHasPlace from "../interactive/BoxFilterHasPlace"
|
2021-05-23 13:45:00 +00:00
|
|
|
import BoxFilterHasImage from "../interactive/BoxFilterHasImage"
|
2021-05-24 12:23:11 +00:00
|
|
|
import BoxFilterIsNotRetweet from "../interactive/BoxFilterIsNotRetweet"
|
2021-05-25 02:06:14 +00:00
|
|
|
import PageWithHeader from "../base/layout/PageWithHeader"
|
|
|
|
import ButtonHeader from "../base/ButtonHeader"
|
|
|
|
import AlertError from "../interactive/AlertError"
|
2021-05-21 14:37:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
export default function RepositoryViewer({ id, className, ...props }) {
|
|
|
|
const { strings } = useContext(ContextLanguage)
|
|
|
|
|
|
|
|
// State
|
|
|
|
const [visualizationTab, setVisualizationTab] = useState("stats")
|
|
|
|
const [filterTab, setFilterTab] = useState("contains")
|
|
|
|
const {
|
|
|
|
value: filters,
|
|
|
|
setValue: setFilters,
|
|
|
|
appendValue: appendFilter,
|
|
|
|
spliceValue: spliceFilter,
|
2021-05-21 17:52:56 +00:00
|
|
|
removeValue: removeFilter,
|
2021-05-21 14:37:30 +00:00
|
|
|
} = useArrayState([])
|
|
|
|
|
2021-05-21 17:52:56 +00:00
|
|
|
// FIXME: this has a severe performance impact, investigate
|
2021-05-22 02:44:08 +00:00
|
|
|
const mapViewHook = useMapAreaState()
|
2021-05-21 14:37:30 +00:00
|
|
|
|
|
|
|
// Repository
|
2021-05-25 02:06:14 +00:00
|
|
|
const {
|
|
|
|
resource: repository,
|
|
|
|
error: repositoryError,
|
|
|
|
firstLoad: repositoryFirstLoad,
|
|
|
|
} = useBackendResource(
|
2021-05-21 14:37:30 +00:00
|
|
|
`/api/v1/repositories/${id}`,
|
|
|
|
{
|
|
|
|
retrieve: true,
|
|
|
|
edit: true,
|
|
|
|
destroy: true,
|
|
|
|
action: false,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
// Tweets
|
2021-05-25 02:06:14 +00:00
|
|
|
const {
|
|
|
|
resources: tweets,
|
|
|
|
error: tweetsError,
|
|
|
|
firstLoad: tweetsFirstLoad,
|
|
|
|
} = useBackendViewset(
|
2021-05-21 14:37:30 +00:00
|
|
|
`/api/v1/repositories/${id}/tweets/`,
|
|
|
|
"snowflake",
|
|
|
|
{
|
|
|
|
list: true,
|
|
|
|
create: false,
|
|
|
|
retrieve: false,
|
|
|
|
edit: false,
|
|
|
|
destroy: false,
|
|
|
|
command: false,
|
|
|
|
action: false,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
// Filtering
|
2021-05-25 02:06:14 +00:00
|
|
|
const filteredTweets = useMemo(
|
|
|
|
() => {
|
|
|
|
let tempTweets = tweets
|
|
|
|
for(const filter of filters) {
|
|
|
|
tempTweets = tempTweets.filter(tweet => filter.exec(tweet))
|
|
|
|
}
|
|
|
|
return tempTweets
|
|
|
|
},
|
|
|
|
[tweets, filters]
|
|
|
|
)
|
2021-05-21 14:37:30 +00:00
|
|
|
|
|
|
|
// Words
|
|
|
|
const words = useMemo(
|
2021-05-25 02:06:14 +00:00
|
|
|
() => objectToWordcloudFormat(countTweetWords(filteredTweets)),
|
|
|
|
[filteredTweets],
|
2021-05-21 14:37:30 +00:00
|
|
|
)
|
|
|
|
|
2021-05-25 02:06:14 +00:00
|
|
|
// Page header
|
|
|
|
const header = useMemo(
|
|
|
|
() => (
|
|
|
|
<BoxHeader>
|
|
|
|
<FontAwesomeIcon icon={repository?.is_active ? faFolderOpen : faFolder}/> {repository?.name}
|
2021-05-21 14:37:30 +00:00
|
|
|
</BoxHeader>
|
2021-05-25 02:06:14 +00:00
|
|
|
),
|
|
|
|
[repository?.is_active, repository?.name]
|
|
|
|
)
|
2021-05-21 14:37:30 +00:00
|
|
|
|
2021-05-25 02:06:14 +00:00
|
|
|
// Page contents
|
|
|
|
const contents = useMemo(
|
|
|
|
() => {
|
|
|
|
if(!repositoryFirstLoad || !tweetsFirstLoad) {
|
|
|
|
return <Loading/>
|
|
|
|
}
|
|
|
|
else if(repositoryError) {
|
|
|
|
return <AlertError error={repositoryError}/>
|
|
|
|
}
|
|
|
|
else if(tweetsError) {
|
|
|
|
return <AlertError error={tweetsError}/>
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return (
|
|
|
|
<div className={Style.RepositoryViewer}>
|
|
|
|
<BoxRepositoryTweets className={Style.Tweets}/>
|
|
|
|
<PickerVisualization className={Style.VisualizationPicker}/>
|
|
|
|
{visualizationTab === "wordcloud" ? <BoxVisualizationWordcloud className={Style.Visualization}/> : null}
|
|
|
|
{visualizationTab === "chart" ? <BoxVisualizationChart className={Style.Visualization}/> : null}
|
|
|
|
{visualizationTab === "map" ? <BoxVisualizationMap className={Style.Visualization}/> : null}
|
|
|
|
{visualizationTab === "stats" ? <BoxVisualizationStats className={Style.Visualization}/> : null}
|
|
|
|
|
|
|
|
<BoxFilters className={Style.Filters}/>
|
|
|
|
<PickerFilter className={Style.FilterPicker}/>
|
|
|
|
{filterTab === "contains" ? <BoxFilterContains className={Style.AddFilter}/> : null}
|
|
|
|
{filterTab === "hashtag" ? <BoxFilterHashtag className={Style.AddFilter}/> : null}
|
|
|
|
{filterTab === "user" ? <BoxFilterUser className={Style.AddFilter}/> : null}
|
|
|
|
{filterTab === "retweet" ? <BoxFilterIsNotRetweet className={Style.AddFilter}/> : null}
|
|
|
|
{filterTab === "image" ? <BoxFilterHasImage className={Style.AddFilter}/> : null}
|
|
|
|
{filterTab === "time" ? <BoxFilterDatetime className={Style.AddFilter}/> : null}
|
|
|
|
{filterTab === "place" ? <BoxFilterHasPlace className={Style.AddFilter}/> : null}
|
|
|
|
{filterTab === "location" ? <BoxFilterLocation className={Style.AddFilter}/> : null}
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[repositoryFirstLoad, tweetsFirstLoad, visualizationTab, filterTab]
|
|
|
|
)
|
2021-05-21 14:37:30 +00:00
|
|
|
|
|
|
|
return (
|
2021-05-21 17:52:56 +00:00
|
|
|
<ContextRepositoryViewer.Provider
|
|
|
|
value={{
|
|
|
|
visualizationTab,
|
|
|
|
setVisualizationTab,
|
|
|
|
filterTab,
|
|
|
|
setFilterTab,
|
|
|
|
filters,
|
|
|
|
setFilters,
|
|
|
|
appendFilter,
|
|
|
|
spliceFilter,
|
|
|
|
removeFilter,
|
|
|
|
repository,
|
2021-05-25 02:06:14 +00:00
|
|
|
rawTweets: tweets,
|
|
|
|
tweets: filteredTweets,
|
2021-05-21 17:52:56 +00:00
|
|
|
words,
|
|
|
|
mapViewHook,
|
|
|
|
}}
|
|
|
|
>
|
2021-05-25 02:06:14 +00:00
|
|
|
<PageWithHeader header={header}>
|
2021-05-21 14:37:30 +00:00
|
|
|
{contents}
|
2021-05-25 02:06:14 +00:00
|
|
|
</PageWithHeader>
|
2021-05-21 14:37:30 +00:00
|
|
|
</ContextRepositoryViewer.Provider>
|
|
|
|
)
|
|
|
|
}
|