diff --git a/schema.json b/schema.json
index d573cbf9..0630ffdf 100644
--- a/schema.json
+++ b/schema.json
@@ -4952,6 +4952,47 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "saveMetacardFromJson",
+ "description": "TBD: Should only be used when updating assocations with IDs\ncreateMetacardFromJson(attrs: Json!): MetacardAttributes",
+ "args": [
+ {
+ "name": "id",
+ "description": "",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "attributes",
+ "description": "",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Json",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "MetacardAttributes",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "deleteMetacard",
"description": "",
diff --git a/src/main/webapp/components/query-selector/query-selector.js b/src/main/webapp/components/query-selector/query-selector.js
index 33d2fe2f..e4abc4b6 100644
--- a/src/main/webapp/components/query-selector/query-selector.js
+++ b/src/main/webapp/components/query-selector/query-selector.js
@@ -11,6 +11,7 @@ import {
IndexCardItem,
} from '../index-cards'
import AdvancedSearchQueryBuilder from '../query-builder/query-builder'
+
const { useDrawInterface } = require('../../react-hooks')
const useOpenClose = props => {
diff --git a/src/main/webapp/components/workspaces/workspaces.js b/src/main/webapp/components/workspaces/workspaces.js
index f6c0563b..dd0aae03 100644
--- a/src/main/webapp/components/workspaces/workspaces.js
+++ b/src/main/webapp/components/workspaces/workspaces.js
@@ -5,9 +5,13 @@ import Tab from '@material-ui/core/Tab'
import Tabs from '@material-ui/core/Tabs'
import Typography from '@material-ui/core/Typography'
import gql from 'graphql-tag'
+import Popover from '@material-ui/core/Popover'
+import Button from '@material-ui/core/Button'
import { getIn } from 'immutable'
import React, { useState } from 'react'
import loadable from 'react-loadable'
+import SaveAltIcon from '@material-ui/icons/SaveAlt'
+import TextField from '@material-ui/core/TextField'
import { Link, Redirect, useParams } from 'react-router-dom'
import { useQueryExecutor } from '../../react-hooks'
import {
@@ -23,9 +27,14 @@ import { InlineRetry, SnackbarRetry } from '../network-retry'
import QueryEditor from '../query-editor'
import QuerySelector from '../query-selector'
import QueryStatus from '../query-status'
+import SearchIcon from '@material-ui/icons/Search'
const LoadingComponent = () =>
+const {
+ transformFilterToCQL,
+} = require('../../intrigue-api/metacards/CQLUtils')
+
let Visualizations = () => null
if (typeof window !== 'undefined') {
Visualizations = loadable({
@@ -59,6 +68,181 @@ const workspaceById = gql`
}
}
`
+const queryAttributes = gql`
+ fragment QueryAttributes on MetacardAttributes {
+ title
+ cql
+ metacard_tags
+ metacard_type
+ }
+`
+
+const useCreateQuery = workspaceId => {
+ const [queryId, setQueryId] = React.useState('')
+ const mutation = gql`
+ mutation CreateQuery($attrs: MetacardAttributesInput!) {
+ createMetacard(attrs: $attrs) {
+ id: id
+ ...QueryAttributes
+ }
+ }
+ ${queryAttributes}
+ `
+
+ const saveMutation = gql`
+ mutation SaveWorkspace($id: ID!, $attributes: Json!) {
+ saveMetacardFromJson(id: $id, attributes: $attributes) {
+ ...WorkspaceAttributes
+ }
+ }
+ ${workspaceAttributes}
+ `
+
+ const [save] = useMutation(saveMutation)
+
+ const [create] = useMutation(mutation, {
+ onCompleted: data => {
+ save({
+ variables: {
+ id: workspaceId,
+ attributes: {
+ queries: [data.createMetacard.id],
+ metacard_type: 'workspace',
+ },
+ },
+ refetchQueries: ['WorkspaceById'],
+ }),
+ setQueryId(data.createMetacard.id)
+ },
+ })
+
+ return [create, queryId]
+}
+
+const TextSearchForm = props => {
+ const [textValue, setTextValue] = React.useState('')
+ const [title, setTitle] = React.useState('')
+ const [create, queryId] = useCreateQuery(props.workspaceId)
+ const { runQuery } = React.useContext(WorkspaceContext)
+
+ const onCreate = async () => {
+ const filter = {
+ property: 'anyText',
+ type: 'ILIKE',
+ value: textValue,
+ }
+
+ const cql = transformFilterToCQL(filter)
+ try {
+ await create({
+ variables: {
+ attrs: {
+ title: title,
+ cql: cql,
+ metacard_tags: ['query'],
+ metacard_type: 'metacard.query',
+ },
+ },
+ })
+ } catch (err) {
+ //eslint-disable-next-line
+ console.err('Error creating search or updating workspace: ', err)
+ }
+ }
+
+ // When the query id actually exists, run it.
+ React.useEffect(
+ () => {
+ if (queryId) {
+ // Get query
+ runQuery(queryId)
+ }
+ },
+ [queryId, runQuery]
+ )
+
+ const onClickSearch = async () => {
+ await onCreate(true)
+ }
+
+ return (
+
+ setTitle(e.target.value)}
+ />
+
+ setTextValue(e.target.value)}
+ />
+
+
+
+
+ )
+}
+
+const useOpenClose = () => {
+ const [anchorEl, setAnchorEl] = React.useState(null)
+ const handleClick = () => {
+ setAnchorEl(event.currentTarget)
+ }
+
+ const handleClose = () => {
+ setAnchorEl(null)
+ }
+
+ const open = Boolean(anchorEl)
+ return [open, anchorEl, handleClose, handleClick]
+}
+
+const EmptySearchCard = props => {
+ const [open, anchorEl, handleClose, handleClick] = useOpenClose()
+ return (
+
+
+ New searches will appear here
+
+
+
+
+
+
+
+
+ )
+}
//TODO add paging
const Results = ({ results }) =>
@@ -74,30 +258,58 @@ const Results = ({ results }) =>
[results]
)
+const WorkspaceContext = React.createContext({
+ runQuery: () => {},
+})
+
export const Workspace = () => {
const { id } = useParams()
const [listResults, setListResults] = React.useState([])
const [currentQuery, setCurrentQuery] = useState(null)
const [queries, setQueries] = useState([])
+ const [queryIdToRun, setQueryIdToRun] = useState(null)
const { results, status, onSearch, onCancel, onClear } = useQueryExecutor()
-
const [tab, setTab] = React.useState(0)
const { loading, error, data } = useQuery(workspaceById, {
variables: { ids: [id] },
- onCompleted: data => {
- const queries = data.metacardsById[0].attributes[0].queries
- setQueries(
- queries.map(query => {
- const { cql, __typename, ...rest } = query // eslint-disable-line no-unused-vars
- return rest
- })
- )
- setCurrentQuery(queries[0] ? queries[0].id : null)
- },
})
+ React.useEffect(
+ () => {
+ if (data) {
+ const queries = data.metacardsById[0].attributes[0].queries
+ setQueries(
+ queries.map(query => {
+ const { cql, __typename, ...rest } = query // eslint-disable-line no-unused-vars
+ return rest
+ })
+ )
+ setCurrentQuery(queries[0] ? queries[0].id : null)
+ }
+ },
+ [data]
+ )
+
+ React.useEffect(
+ () => {
+ if (data && queryIdToRun) {
+ const queryToRun = data.metacardsById[0].attributes[0].queries.find(
+ q => q.id === queryIdToRun
+ )
+ if (queryToRun !== undefined) {
+ onSearch(queryToRun)
+ }
+ }
+ },
+ [queryIdToRun, data, onSearch]
+ )
+
+ const runQuery = queryId => {
+ setQueryIdToRun(queryId)
+ }
+
if (loading) {
return
}
@@ -107,103 +319,106 @@ export const Workspace = () => {
}
const attributes = data.metacardsById[0].attributes[0]
-
const { title, lists } = attributes
const hasQueries = queries && queries.length > 0
return (
-
+
-
- {title}
-
-
-
-
setTab(selectedIndex)}
- indicatorColor="primary"
- textColor="primary"
- variant="fullWidth"
+
-
-
-
+
+ {title}
+
+
+
+
setTab(selectedIndex)}
+ indicatorColor="primary"
+ textColor="primary"
+ variant="fullWidth"
+ >
+
+
+
+
+ {tab === 0 &&
+ (hasQueries ? (
+
+ {/* //TODO mutate cache on search so that the queries reflect edits made in queryEditor */}
+ {
+ onClear()
+ setCurrentQuery(query.id)
+ onSearch(query)
+ }}
+ onChange={queries => setQueries(queries)}
+ />
- {tab === 0 &&
- hasQueries && (
+ {
+ //setPageIndex(0)
+ onSearch({
+ ...queries.find(query => (query.id = currentQuery)),
+ srcs,
+ })
+ }}
+ onCancel={srcs => {
+ srcs.forEach(src => {
+ onCancel(src)
+ })
+ }}
+ />
+
+
+ ) : (
+
+ ))}
+
+ {tab === 1 && (
- {/* //TODO mutate cache on search so that the queries reflect edits made in queryEditor */}
- {
- onClear()
- setCurrentQuery(query.id)
- onSearch(query)
+ {
+ const results = data.metacardsById.reduce((acc, metacard) => {
+ return acc.concat(metacard.results)
+ }, [])
+ setListResults(results)
}}
- onChange={queries => setQueries(queries)}
/>
- {
- //setPageIndex(0)
- onSearch({
- ...queries.find(query => (query.id = currentQuery)),
- srcs,
- })
- }}
- onCancel={srcs => {
- srcs.forEach(src => {
- onCancel(src)
- })
- }}
- />
-
+ {listResults.map(({ metacard }) => (
+
+ ))}
)}
-
- {tab === 1 && (
-
- {
- const results = data.metacardsById.reduce((acc, metacard) => {
- return acc.concat(metacard.results)
- }, [])
- setListResults(results)
- }}
- />
-
- {listResults.map(({ metacard }) => (
-
- ))}
-
- )}
-
-
-
+
+
+
+
-
+
)
}
@@ -259,7 +474,7 @@ const workspaceAttributes = gql`
}
`
-const useCreate = () => {
+const useCreateWorkspace = () => {
const [redirectId, setRedirectId] = React.useState(null)
const mutation = gql`
mutation CreateWorkspace($attrs: MetacardAttributesInput!) {
@@ -326,7 +541,7 @@ const useDelete = () => {
export default () => {
const { refetch, loading, error, data } = useQuery(workspaces)
- const [create, redirectId] = useCreate()
+ const [create, redirectId] = useCreateWorkspace()
const [_delete] = useDelete()
if (loading) {
diff --git a/src/main/webapp/intrigue-api/metacards/metacards.js b/src/main/webapp/intrigue-api/metacards/metacards.js
index 66ae5e8b..d5c10f3e 100644
--- a/src/main/webapp/intrigue-api/metacards/metacards.js
+++ b/src/main/webapp/intrigue-api/metacards/metacards.js
@@ -123,9 +123,9 @@ const typeDefs = `
createMetacard(attrs: MetacardAttributesInput!): MetacardAttributes
saveMetacard(id: ID!, attributes: MetacardAttributesInput!): MetacardAttributes
- # TBD: Should only be used when...
+ # TBD: Should only be used when updating assocations with IDs
# createMetacardFromJson(attrs: Json!): MetacardAttributes
- # saveMetacardFromJson(id: ID!, attrs: Json!): MetacardAttributes
+ saveMetacardFromJson(id: ID!, attributes: Json!): MetacardAttributes
deleteMetacard(id: ID!): ID
}
@@ -423,6 +423,7 @@ const saveMetacard = async (parent, args, context) => {
)
const [oldMetacardAttrs] = oldMetacard.attributes
const { catalog, fromGraphqlName, toGraphqlName } = context
+
if (attributes.filterTree) {
attributes = setIn(
attributes,
@@ -475,6 +476,7 @@ const resolvers = {
Mutation: {
createMetacard,
saveMetacard,
+ saveMetacardFromJson: saveMetacard,
deleteMetacard,
},
}