Show Data Store tiles on the Process Group page (#917)
Co-authored-by: Kevin Burnett <18027+burnettk@users.noreply.github.com>
This commit is contained in:
parent
858e8eaec4
commit
4758634c99
|
@ -305,7 +305,7 @@ paths:
|
|||
- name: per_page
|
||||
in: query
|
||||
required: false
|
||||
description: The number of groups to show per page. Defaults to page 10.
|
||||
description: The number of groups to show per page. Defaults to 10.
|
||||
schema:
|
||||
type: integer
|
||||
get:
|
||||
|
@ -449,7 +449,7 @@ paths:
|
|||
- name: per_page
|
||||
in: query
|
||||
required: false
|
||||
description: The number of models to show per page. Defaults to page 10.
|
||||
description: The number of models to show per page. Defaults to 10.
|
||||
schema:
|
||||
type: integer
|
||||
get:
|
||||
|
@ -2439,7 +2439,7 @@ paths:
|
|||
- name: per_page
|
||||
in: query
|
||||
required: false
|
||||
description: The number of models to show per page. Defaults to page 10.
|
||||
description: The number of models to show per page. Defaults to 10.
|
||||
schema:
|
||||
type: integer
|
||||
get:
|
||||
|
@ -2498,7 +2498,7 @@ paths:
|
|||
- name: per_page
|
||||
in: query
|
||||
required: false
|
||||
description: The number of items to show per page. Defaults to page 10.
|
||||
description: The number of items to show per page. Defaults to 10.
|
||||
schema:
|
||||
type: integer
|
||||
- name: events
|
||||
|
@ -2621,7 +2621,7 @@ paths:
|
|||
- name: per_page
|
||||
in: query
|
||||
required: false
|
||||
description: The number of items to show per page. Defaults to page 10.
|
||||
description: The number of items to show per page. Defaults to 10.
|
||||
schema:
|
||||
type: integer
|
||||
post:
|
||||
|
@ -2759,6 +2759,25 @@ paths:
|
|||
# - application/json
|
||||
|
||||
/data-stores:
|
||||
parameters:
|
||||
- name: process_group_identifier
|
||||
in: query
|
||||
required: false
|
||||
description: Optional parameter to filter by a single group
|
||||
schema:
|
||||
type: string
|
||||
- name: page
|
||||
in: query
|
||||
required: false
|
||||
description: The page number to return. Defaults to page 1.
|
||||
schema:
|
||||
type: integer
|
||||
- name: per_page
|
||||
in: query
|
||||
required: false
|
||||
description: The number of groups to show per page. Defaults to 10.
|
||||
schema:
|
||||
type: integer
|
||||
get:
|
||||
operationId: spiffworkflow_backend.routes.data_store_controller.data_store_list
|
||||
summary: Return a list of the data store objects.
|
||||
|
@ -2780,6 +2799,19 @@ paths:
|
|||
responses:
|
||||
"200":
|
||||
description: The newly created data store instance
|
||||
put:
|
||||
operationId: spiffworkflow_backend.routes.data_store_controller.data_store_update
|
||||
summary: Update a data store instance.
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/DataStore"
|
||||
tags:
|
||||
- Data Stores
|
||||
responses:
|
||||
"200":
|
||||
description: The updated data store instance
|
||||
/data-stores/types:
|
||||
get:
|
||||
operationId: spiffworkflow_backend.routes.data_store_controller.data_store_types
|
||||
|
@ -2789,7 +2821,7 @@ paths:
|
|||
responses:
|
||||
"200":
|
||||
description: The list of currently defined data store types
|
||||
/data-stores/{data_store_type}/{name}:
|
||||
/data-stores/{data_store_type}/{name}/items:
|
||||
parameters:
|
||||
- name: data_store_type
|
||||
in: path
|
||||
|
@ -2823,6 +2855,34 @@ paths:
|
|||
responses:
|
||||
"200":
|
||||
description: A list of the data stored in the requested data store.
|
||||
/data-stores/{data_store_type}/{identifier}:
|
||||
parameters:
|
||||
- name: data_store_type
|
||||
in: path
|
||||
required: true
|
||||
description: The type of datastore, such as "typeahead"
|
||||
schema:
|
||||
type: string
|
||||
- name: identifier
|
||||
in: path
|
||||
required: true
|
||||
description: The identifier of the datastore, such as "cities"
|
||||
schema:
|
||||
type: string
|
||||
- name: process_group_identifier
|
||||
in: query
|
||||
required: true
|
||||
description: The process group
|
||||
schema:
|
||||
type: string
|
||||
get:
|
||||
operationId: spiffworkflow_backend.routes.data_store_controller.data_store_show
|
||||
summary: Returns a description of the data store.
|
||||
tags:
|
||||
- Data Stores
|
||||
responses:
|
||||
"200":
|
||||
description: The requested data store.
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
|
|
|
@ -3,15 +3,19 @@ from typing import Any
|
|||
|
||||
class DataStoreCRUD:
|
||||
@staticmethod
|
||||
def create_instance(name: str, identifier: str, location: str, schema: dict[str, Any], description: str | None) -> None:
|
||||
def create_instance(identifier: str, location: str) -> Any:
|
||||
raise Exception("must implement")
|
||||
|
||||
@staticmethod
|
||||
def existing_data_stores() -> list[dict[str, Any]]:
|
||||
def existing_instance(identifier: str, location: str) -> Any:
|
||||
raise Exception("must implement")
|
||||
|
||||
@staticmethod
|
||||
def query_data_store(name: str) -> Any:
|
||||
def existing_data_stores(process_group_identifier: str | None = None) -> list[dict[str, Any]]:
|
||||
raise Exception("must implement")
|
||||
|
||||
@staticmethod
|
||||
def get_data_store_query(name: str, process_group_identifier: str | None) -> Any:
|
||||
raise Exception("must implement")
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -33,32 +33,38 @@ class JSONDataStore(BpmnDataStoreSpecification, DataStoreCRUD): # type: ignore
|
|||
"""JSONDataStore."""
|
||||
|
||||
@staticmethod
|
||||
def create_instance(name: str, identifier: str, location: str, schema: dict[str, Any], description: str | None) -> None:
|
||||
model = JSONDataStoreModel(
|
||||
name=name,
|
||||
def create_instance(identifier: str, location: str) -> Any:
|
||||
return JSONDataStoreModel(
|
||||
identifier=identifier,
|
||||
location=location,
|
||||
schema=schema,
|
||||
description=description or "",
|
||||
data={},
|
||||
)
|
||||
db.session.add(model)
|
||||
db.session.commit()
|
||||
|
||||
@staticmethod
|
||||
def existing_data_stores() -> list[dict[str, Any]]:
|
||||
def existing_instance(identifier: str, location: str) -> Any:
|
||||
return db.session.query(JSONDataStoreModel).filter_by(identifier=identifier, location=location).first()
|
||||
|
||||
@staticmethod
|
||||
def existing_data_stores(process_group_identifier: str | None = None) -> list[dict[str, Any]]:
|
||||
data_stores = []
|
||||
|
||||
query = db.session.query(JSONDataStoreModel.name, JSONDataStoreModel.identifier)
|
||||
if process_group_identifier is not None:
|
||||
query = query.filter_by(location=process_group_identifier)
|
||||
keys = query.distinct().order_by(JSONDataStoreModel.name).all() # type: ignore
|
||||
for key in keys:
|
||||
data_stores.append({"name": key[0], "type": "json", "identifier": key[1], "clz": "JSONDataStore"})
|
||||
data_stores.append({"name": key[0], "type": "json", "id": key[1], "clz": "JSONDataStore"})
|
||||
|
||||
return data_stores
|
||||
|
||||
@staticmethod
|
||||
def query_data_store(name: str) -> Any:
|
||||
return JSONDataStoreModel.query.filter_by(name=name).order_by(JSONDataStoreModel.name)
|
||||
def get_data_store_query(identifier: str, process_group_identifier: str | None) -> Any:
|
||||
query = JSONDataStoreModel.query
|
||||
if process_group_identifier is not None:
|
||||
query = query.filter_by(identifier=identifier, location=process_group_identifier)
|
||||
else:
|
||||
query = query.filter_by(name=identifier)
|
||||
return query.order_by(JSONDataStoreModel.name)
|
||||
|
||||
@staticmethod
|
||||
def build_response_item(model: Any) -> dict[str, Any]:
|
||||
|
|
|
@ -13,8 +13,12 @@ class KKVDataStore(BpmnDataStoreSpecification, DataStoreCRUD): # type: ignore
|
|||
"""KKVDataStore."""
|
||||
|
||||
@staticmethod
|
||||
def existing_data_stores() -> list[dict[str, Any]]:
|
||||
data_stores = []
|
||||
def existing_data_stores(process_group_identifier: str | None = None) -> list[dict[str, Any]]:
|
||||
data_stores: list[dict[str, Any]] = []
|
||||
|
||||
if process_group_identifier is not None:
|
||||
# temporary until this data store gets location support
|
||||
return data_stores
|
||||
|
||||
keys = (
|
||||
db.session.query(KKVDataStoreModel.top_level_key)
|
||||
|
@ -23,12 +27,12 @@ class KKVDataStore(BpmnDataStoreSpecification, DataStoreCRUD): # type: ignore
|
|||
.all()
|
||||
)
|
||||
for key in keys:
|
||||
data_stores.append({"name": key[0], "type": "kkv", "identifier": "", "clz": "KKVDataStore"})
|
||||
data_stores.append({"name": key[0], "type": "kkv", "id": "", "clz": "KKVDataStore"})
|
||||
|
||||
return data_stores
|
||||
|
||||
@staticmethod
|
||||
def query_data_store(name: str) -> Any:
|
||||
def get_data_store_query(name: str, process_group_identifier: str | None) -> Any:
|
||||
return KKVDataStoreModel.query.filter_by(top_level_key=name).order_by(
|
||||
KKVDataStoreModel.top_level_key, KKVDataStoreModel.secondary_key
|
||||
)
|
||||
|
|
|
@ -14,17 +14,21 @@ class TypeaheadDataStore(BpmnDataStoreSpecification, DataStoreCRUD): # type: ig
|
|||
"""TypeaheadDataStore."""
|
||||
|
||||
@staticmethod
|
||||
def existing_data_stores() -> list[dict[str, Any]]:
|
||||
data_stores = []
|
||||
def existing_data_stores(process_group_identifier: str | None = None) -> list[dict[str, Any]]:
|
||||
data_stores: list[dict[str, Any]] = []
|
||||
|
||||
if process_group_identifier is not None:
|
||||
# temporary until this data store gets location support
|
||||
return data_stores
|
||||
|
||||
keys = db.session.query(TypeaheadModel.category).distinct().order_by(TypeaheadModel.category).all() # type: ignore
|
||||
for key in keys:
|
||||
data_stores.append({"name": key[0], "type": "typeahead", "identifier": key[0], "clz": "TypeaheadDataStore"})
|
||||
data_stores.append({"name": key[0], "type": "typeahead", "id": key[0], "clz": "TypeaheadDataStore"})
|
||||
|
||||
return data_stores
|
||||
|
||||
@staticmethod
|
||||
def query_data_store(name: str) -> Any:
|
||||
def get_data_store_query(name: str, process_group_identifier: str | None) -> Any:
|
||||
return TypeaheadModel.query.filter_by(category=name).order_by(TypeaheadModel.category, TypeaheadModel.search_term)
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -10,6 +10,7 @@ from spiffworkflow_backend.data_stores.json import JSONDataStore
|
|||
from spiffworkflow_backend.data_stores.kkv import KKVDataStore
|
||||
from spiffworkflow_backend.data_stores.typeahead import TypeaheadDataStore
|
||||
from spiffworkflow_backend.exceptions.api_error import ApiError
|
||||
from spiffworkflow_backend.models.db import db
|
||||
|
||||
DATA_STORES = {
|
||||
"json": (JSONDataStore, "JSON Data Store"),
|
||||
|
@ -18,15 +19,15 @@ DATA_STORES = {
|
|||
}
|
||||
|
||||
|
||||
def data_store_list() -> flask.wrappers.Response:
|
||||
def data_store_list(process_group_identifier: str | None = None, page: int = 1, per_page: int = 100) -> flask.wrappers.Response:
|
||||
"""Returns a list of the names of all the data stores."""
|
||||
data_stores = []
|
||||
|
||||
# Right now the only data stores we support are type ahead, kkv, json
|
||||
|
||||
data_stores.extend(JSONDataStore.existing_data_stores())
|
||||
data_stores.extend(TypeaheadDataStore.existing_data_stores())
|
||||
data_stores.extend(KKVDataStore.existing_data_stores())
|
||||
data_stores.extend(JSONDataStore.existing_data_stores(process_group_identifier))
|
||||
data_stores.extend(TypeaheadDataStore.existing_data_stores(process_group_identifier))
|
||||
data_stores.extend(KKVDataStore.existing_data_stores(process_group_identifier))
|
||||
|
||||
return make_response(jsonify(data_stores), 200)
|
||||
|
||||
|
@ -42,7 +43,7 @@ def data_store_types() -> flask.wrappers.Response:
|
|||
|
||||
|
||||
def _build_response(data_store_class: Any, name: str, page: int, per_page: int) -> flask.wrappers.Response:
|
||||
data_store_query = data_store_class.query_data_store(name)
|
||||
data_store_query = data_store_class.get_data_store_query(name, None)
|
||||
data = data_store_query.paginate(page=page, per_page=per_page, error_out=False)
|
||||
results = []
|
||||
for item in data.items:
|
||||
|
@ -70,6 +71,14 @@ def data_store_item_list(data_store_type: str, name: str, page: int = 1, per_pag
|
|||
|
||||
|
||||
def data_store_create(body: dict) -> flask.wrappers.Response:
|
||||
return _data_store_upsert(body, True)
|
||||
|
||||
|
||||
def data_store_update(body: dict) -> flask.wrappers.Response:
|
||||
return _data_store_upsert(body, False)
|
||||
|
||||
|
||||
def _data_store_upsert(body: dict, insert: bool) -> flask.wrappers.Response:
|
||||
try:
|
||||
data_store_type = body["type"]
|
||||
name = body["name"]
|
||||
|
@ -97,6 +106,46 @@ def data_store_create(body: dict) -> flask.wrappers.Response:
|
|||
raise ApiError("unknown_data_store", f"Unknown data store type: {data_store_type}", status_code=400)
|
||||
|
||||
data_store_class, _ = DATA_STORES[data_store_type]
|
||||
data_store_class.create_instance(name, identifier, location, schema, description)
|
||||
|
||||
if insert:
|
||||
model = data_store_class.create_instance(identifier, location)
|
||||
else:
|
||||
model = data_store_class.existing_instance(identifier, location)
|
||||
|
||||
model.name = name
|
||||
model.schema = schema
|
||||
model.description = description or ""
|
||||
|
||||
db.session.add(model)
|
||||
db.session.commit()
|
||||
|
||||
return make_response(jsonify({"ok": True}), 200)
|
||||
|
||||
|
||||
def data_store_show(data_store_type: str, identifier: str, process_group_identifier: str) -> flask.wrappers.Response:
|
||||
"""Returns a description of a data store."""
|
||||
|
||||
if data_store_type not in DATA_STORES:
|
||||
raise ApiError("unknown_data_store", f"Unknown data store type: {data_store_type}", status_code=400)
|
||||
|
||||
data_store_class, _ = DATA_STORES[data_store_type]
|
||||
data_store_query = data_store_class.get_data_store_query(identifier, process_group_identifier)
|
||||
result = data_store_query.first()
|
||||
|
||||
if result is None:
|
||||
raise ApiError(
|
||||
"could_not_locate_data_store",
|
||||
f"Could not locate data store type: {data_store_type} for process group: {process_group_identifier}",
|
||||
status_code=400,
|
||||
)
|
||||
|
||||
response = {
|
||||
"name": result.name,
|
||||
"location": result.location,
|
||||
"type": data_store_type,
|
||||
"id": result.identifier,
|
||||
"schema": result.schema,
|
||||
"description": result.description,
|
||||
}
|
||||
|
||||
return make_response(jsonify(response), 200)
|
||||
|
|
|
@ -67,8 +67,8 @@ class TestDataStores(BaseTest):
|
|||
self.load_data_store(app, client, with_db_and_bpmn_file_cleanup, with_super_admin_user)
|
||||
results = client.get("/v1.0/data-stores", headers=self.logged_in_headers(with_super_admin_user))
|
||||
assert results.json == [
|
||||
{"name": "albums", "type": "typeahead", "identifier": "albums", "clz": "TypeaheadDataStore"},
|
||||
{"name": "cereals", "type": "typeahead", "identifier": "cereals", "clz": "TypeaheadDataStore"},
|
||||
{"name": "albums", "type": "typeahead", "id": "albums", "clz": "TypeaheadDataStore"},
|
||||
{"name": "cereals", "type": "typeahead", "id": "cereals", "clz": "TypeaheadDataStore"},
|
||||
]
|
||||
|
||||
def test_get_data_store_returns_paginated_results(
|
||||
|
@ -80,7 +80,7 @@ class TestDataStores(BaseTest):
|
|||
) -> None:
|
||||
self.load_data_store(app, client, with_db_and_bpmn_file_cleanup, with_super_admin_user)
|
||||
response = client.get(
|
||||
"/v1.0/data-stores/typeahead/albums?per_page=10", headers=self.logged_in_headers(with_super_admin_user)
|
||||
"/v1.0/data-stores/typeahead/albums/items?per_page=10", headers=self.logged_in_headers(with_super_admin_user)
|
||||
)
|
||||
|
||||
expected_item_in_response = {
|
||||
|
|
|
@ -49,7 +49,11 @@ export default function DataStoreForm({
|
|||
|
||||
useEffect(() => {
|
||||
const handleSetDataStoreTypesCallback = (result: any) => {
|
||||
const dataStoreType = result.find((item: any) => {
|
||||
return item.type === dataStore.type;
|
||||
});
|
||||
setDataStoreTypes(result);
|
||||
setSelectedDataStoreType(dataStoreType ?? null);
|
||||
};
|
||||
|
||||
HttpService.makeCallToBackend({
|
||||
|
@ -57,7 +61,7 @@ export default function DataStoreForm({
|
|||
successCallback: handleSetDataStoreTypesCallback,
|
||||
httpMethod: 'GET',
|
||||
});
|
||||
}, [setDataStoreTypes]);
|
||||
}, [dataStore, setDataStoreTypes]);
|
||||
|
||||
const navigateToDataStores = (_result: any) => {
|
||||
const location = dataStoreLocation();
|
||||
|
@ -99,10 +103,9 @@ export default function DataStoreForm({
|
|||
if (hasErrors) {
|
||||
return;
|
||||
}
|
||||
let path = '/data-stores';
|
||||
const path = '/data-stores';
|
||||
let httpMethod = 'POST';
|
||||
if (mode === 'edit') {
|
||||
path = `/data-stores/${dataStore.id}`;
|
||||
httpMethod = 'PUT';
|
||||
}
|
||||
const postBody = {
|
||||
|
@ -177,26 +180,25 @@ export default function DataStoreForm({
|
|||
/>,
|
||||
];
|
||||
|
||||
if (mode === 'new') {
|
||||
textInputs.push(
|
||||
<TextInput
|
||||
id="data-store-identifier"
|
||||
name="id"
|
||||
invalidText="Identifier is required and must be all lowercase characters and hyphens."
|
||||
invalid={identifierInvalid}
|
||||
labelText="Identifier*"
|
||||
value={dataStore.id}
|
||||
onChange={(event: any) => {
|
||||
updateDataStore({ id: event.target.value });
|
||||
// was invalid, and now valid
|
||||
if (identifierInvalid && hasValidIdentifier(event.target.value)) {
|
||||
setIdentifierInvalid(false);
|
||||
}
|
||||
setIdHasBeenUpdatedByUser(true);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
textInputs.push(
|
||||
<TextInput
|
||||
id="data-store-identifier"
|
||||
name="id"
|
||||
readonly={mode === 'edit'}
|
||||
invalidText="Identifier is required and must be all lowercase characters and hyphens."
|
||||
invalid={identifierInvalid}
|
||||
labelText="Identifier*"
|
||||
value={dataStore.id}
|
||||
onChange={(event: any) => {
|
||||
updateDataStore({ id: event.target.value });
|
||||
// was invalid, and now valid
|
||||
if (identifierInvalid && hasValidIdentifier(event.target.value)) {
|
||||
setIdentifierInvalid(false);
|
||||
}
|
||||
setIdHasBeenUpdatedByUser(true);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
textInputs.push(
|
||||
<ComboBox
|
||||
|
|
|
@ -51,7 +51,7 @@ export default function DataStoreListTable() {
|
|||
}
|
||||
const queryParamString = `per_page=${perPage}&page=${page}`;
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/data-stores/${dataStoreType}/${dataStoreName}?${queryParamString}`,
|
||||
path: `/data-stores/${dataStoreType}/${dataStoreName}/items?${queryParamString}`,
|
||||
successCallback: (response: DataStoreRecords) => {
|
||||
setResults(response.results);
|
||||
setPagination(response.pagination);
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
import { ReactElement, useEffect, useState } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { ArrowRight } from '@carbon/icons-react';
|
||||
import { ClickableTile } from '@carbon/react';
|
||||
import HttpService from '../services/HttpService';
|
||||
import { DataStore, ProcessGroup } from '../interfaces';
|
||||
import { truncateString } from '../helpers';
|
||||
|
||||
type OwnProps = {
|
||||
defaultDataStores?: DataStore[];
|
||||
dataStore?: DataStore;
|
||||
processGroup?: ProcessGroup;
|
||||
headerElement?: ReactElement;
|
||||
showNoItemsDisplayText?: boolean;
|
||||
userCanCreateDataStores?: boolean;
|
||||
};
|
||||
|
||||
export default function DataStoreListTiles({
|
||||
defaultDataStores,
|
||||
dataStore,
|
||||
processGroup,
|
||||
headerElement,
|
||||
showNoItemsDisplayText,
|
||||
userCanCreateDataStores,
|
||||
}: OwnProps) {
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
const [dataStores, setDataStores] = useState<DataStore[] | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const setDataStoresFromResult = (result: any) => {
|
||||
setDataStores(result);
|
||||
};
|
||||
|
||||
if (defaultDataStores) {
|
||||
setDataStores(defaultDataStores);
|
||||
} else {
|
||||
let queryParams = '?per_page=1000';
|
||||
if (processGroup) {
|
||||
queryParams = `${queryParams}&process_group_identifier=${processGroup.id}`;
|
||||
}
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/data-stores${queryParams}`,
|
||||
successCallback: setDataStoresFromResult,
|
||||
});
|
||||
}
|
||||
}, [searchParams, dataStore, defaultDataStores, processGroup]);
|
||||
|
||||
const dataStoresDisplayArea = () => {
|
||||
let displayText = null;
|
||||
if (dataStores && dataStores.length > 0) {
|
||||
displayText = dataStores.map((row: DataStore) => {
|
||||
return (
|
||||
<ClickableTile
|
||||
id={`data-store-tile-${row.id}`}
|
||||
className="tile-data-store"
|
||||
href={`/data-stores/${row.id}/edit?parentGroupId=${
|
||||
processGroup?.id ?? ''
|
||||
}`}
|
||||
>
|
||||
<div className="tile-data-store-content-container">
|
||||
<ArrowRight />
|
||||
<div className="tile-data-store-display-name">{row.name}</div>
|
||||
<p className="tile-description">
|
||||
{truncateString(row.description || '', 100)}
|
||||
</p>
|
||||
</div>
|
||||
</ClickableTile>
|
||||
);
|
||||
});
|
||||
} else if (userCanCreateDataStores) {
|
||||
displayText = (
|
||||
<p className="no-results-message">
|
||||
There are no data stores to display. You can add one by clicking the
|
||||
"Add a data store" button.
|
||||
</p>
|
||||
);
|
||||
} else {
|
||||
displayText = (
|
||||
<p className="no-results-message">
|
||||
There are no data stores to display.
|
||||
</p>
|
||||
);
|
||||
}
|
||||
return displayText;
|
||||
};
|
||||
|
||||
const dataStoreArea = () => {
|
||||
if (dataStores && (showNoItemsDisplayText || dataStores.length > 0)) {
|
||||
return (
|
||||
<>
|
||||
{headerElement}
|
||||
{dataStoresDisplayArea()}
|
||||
</>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
if (dataStores) {
|
||||
return (
|
||||
<>
|
||||
{/* so we can check if the data stores have loaded in cypress tests */}
|
||||
<div data-qa="data-stores-loaded" className="hidden" />
|
||||
{dataStoreArea()}
|
||||
</>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
|
@ -400,6 +400,32 @@ in on this with the react-jsonschema-form repo. This is just a patch fix to allo
|
|||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.cds--tile.tile-data-store {
|
||||
padding: 0px;
|
||||
margin: 12px 24px 12px 0px;
|
||||
width: 320px;
|
||||
height: 264px;
|
||||
background: #f4f4f4;
|
||||
order: 1;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.tile-data-store-content-container {
|
||||
width: 320px;
|
||||
height: 264px;
|
||||
padding: 1rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tile-data-store-display-name {
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
color: #161616;
|
||||
order: 0;
|
||||
}
|
||||
|
||||
.cds--tile.tile-process-group {
|
||||
padding: 0px;
|
||||
margin: 12px 24px 12px 0px;
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
import { useParams, useSearchParams } from 'react-router-dom';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import DataStoreForm from '../components/DataStoreForm';
|
||||
import { DataStore, HotCrumbItem } from '../interfaces';
|
||||
import { setPageTitle } from '../helpers';
|
||||
import HttpService from '../services/HttpService';
|
||||
|
||||
export default function DataStoreEdit() {
|
||||
const params = useParams();
|
||||
const [searchParams] = useSearchParams();
|
||||
const parentGroupId = searchParams.get('parentGroupId');
|
||||
const dataStoreIdentifier = params.data_store_identifier;
|
||||
const [dataStore, setDataStore] = useState<DataStore>({
|
||||
id: '',
|
||||
name: '',
|
||||
type: '',
|
||||
schema: '',
|
||||
description: '',
|
||||
});
|
||||
useEffect(() => {
|
||||
setPageTitle(['Edit Data Store']);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const setDataStoreFromResult = (result: any) => {
|
||||
const schema = JSON.stringify(result.schema);
|
||||
setDataStore({ ...result, schema });
|
||||
};
|
||||
|
||||
const queryParams = `?process_group_identifier=${parentGroupId}`;
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/data-stores/json/${dataStoreIdentifier}${queryParams}`,
|
||||
successCallback: setDataStoreFromResult,
|
||||
});
|
||||
}, [dataStoreIdentifier, parentGroupId]);
|
||||
|
||||
const hotCrumbs: HotCrumbItem[] = [['Process Groups', '/process-groups']];
|
||||
if (parentGroupId) {
|
||||
hotCrumbs.push({
|
||||
entityToExplode: parentGroupId,
|
||||
entityType: 'process-group-id',
|
||||
linkLastItem: true,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ProcessBreadcrumb hotCrumbs={hotCrumbs} />
|
||||
<h1>Edit Data Store</h1>
|
||||
<DataStoreForm
|
||||
mode="edit"
|
||||
dataStore={dataStore}
|
||||
setDataStore={setDataStore}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
import { Route, Routes } from 'react-router-dom';
|
||||
import DataStoreList from './DataStoreList';
|
||||
import DataStoreNew from './DataStoreNew';
|
||||
import DataStoreEdit from './DataStoreEdit';
|
||||
|
||||
export default function DataStoreRoutes() {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/" element={<DataStoreList />} />
|
||||
<Route path=":data_store_identifier/edit" element={<DataStoreEdit />} />
|
||||
<Route path="new" element={<DataStoreNew />} />
|
||||
</Routes>
|
||||
);
|
||||
|
|
|
@ -14,6 +14,7 @@ import { PermissionsToCheck, ProcessGroup } from '../interfaces';
|
|||
import { useUriListForPermissions } from '../hooks/UriListForPermissions';
|
||||
import { usePermissionFetcher } from '../hooks/PermissionService';
|
||||
import ProcessGroupListTiles from '../components/ProcessGroupListTiles';
|
||||
import DataStoreListTiles from '../components/DataStoreListTiles';
|
||||
import ButtonWithConfirmation from '../components/ButtonWithConfirmation';
|
||||
import ProcessModelListTiles from '../components/ProcessModelListTiles';
|
||||
import useProcessGroupFetcher from '../hooks/useProcessGroupFetcher';
|
||||
|
@ -162,6 +163,17 @@ export default function ProcessGroupShow() {
|
|||
targetUris.processGroupListPath
|
||||
)}
|
||||
/>
|
||||
<br />
|
||||
<br />
|
||||
<DataStoreListTiles
|
||||
processGroup={processGroup}
|
||||
headerElement={<h2 className="clear-left">Data Stores</h2>}
|
||||
showNoItemsDisplayText={showNoItemsDisplayText}
|
||||
userCanCreateDataStores={ability.can(
|
||||
'POST',
|
||||
targetUris.dataStoreListPath
|
||||
)}
|
||||
/>
|
||||
</ul>
|
||||
</>
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue