Skip to content

Commit

Permalink
Actions for multiple rows and styling
Browse files Browse the repository at this point in the history
  • Loading branch information
haffi96 committed Nov 19, 2022
1 parent 4246898 commit 87f7968
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 96 deletions.
55 changes: 0 additions & 55 deletions admin_ui/src/components/CallbackButton.vue

This file was deleted.

10 changes: 8 additions & 2 deletions admin_ui/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ export interface DeleteRow {
rowID: number
}

export interface ExecuteCallback {
export interface ExecuteAction {
tableName: string
rowID: number
rowIDs: number
actionId: number
}

export interface UpdateRow {
Expand Down Expand Up @@ -149,3 +150,8 @@ export interface FormConfig {
slug: string
description: string
}

export interface Action {
actionID: number
actionName: string
}
19 changes: 15 additions & 4 deletions admin_ui/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ export default new Vuex.Store({
tableNames: [],
formConfigs: [] as i.FormConfig[],
user: undefined,
loadingStatus: false
loadingStatus: false,
actions: [] as i.Action[]
},
mutations: {
updateTableNames(state, value) {
Expand Down Expand Up @@ -66,6 +67,9 @@ export default new Vuex.Store({
updateSortBy(state, config: i.SortByConfig) {
state.sortBy = config
},
updateActions(state, actions) {
state.actions = actions
},
reset(state) {
state.sortBy = null
state.filterParams = {}
Expand Down Expand Up @@ -229,12 +233,19 @@ export default new Vuex.Store({
)
return response
},
async executeCallback(context, config: i.ExecuteCallback) {
async fetchActions(context, tableName: string) {
const response = await axios.get(
`${BASE_URL}tables/${tableName}/actions`
)
context.commit("updateActions", response.data)
return response
},
async executeAction(context, config: i.ExecuteAction) {
const response = await axios.post(
`${BASE_URL}tables/${config.tableName}/callback/execute`,
`${BASE_URL}tables/${config.tableName}/actions/${config.actionId}/execute`,
{
table_name: config.tableName,
row_id: config.rowID
row_ids: config.rowIDs
}
)
return response
Expand Down
62 changes: 37 additions & 25 deletions admin_ui/src/views/RowListing.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@
/>
</div>
<div class="buttons">
<a class="button" v-on:click.prevent="showActionDropDown = !showActionDropDown">
<font-awesome-icon icon="angle-right" v-if="!showActionDropDown"/>
<font-awesome-icon icon="angle-down" v-if="showActionDropDown"/>
Actions
<a class="actions-dropdown">
<DropDownMenu v-if="showActionDropDown">
<li v-for="action in allActions">
<a href="#" class="button" v-on:click="executeAction(action.action_id)">
<span>{{ action.action_name }}</span>
</a>
</li>
</DropDownMenu>
</a>
</a>
<a
class="button"
href="#"
Expand All @@ -27,7 +41,8 @@
v-if="selectedRows.length > 0"
v-on:triggered="deleteRows"
/>



<router-link
:to="{
name: 'addRow',
Expand All @@ -40,6 +55,7 @@
<span>{{ $t("Add Row") }}</span>
</router-link>


<a
class="button"
href="#"
Expand Down Expand Up @@ -299,17 +315,6 @@
"
/>
</li>
<li>
<CallbackButton
:includeTitle="true"
class=""
v-on:triggered="
executeCallback(
row[pkName]
)
"
/>
</li>
</DropDownMenu>
</span>
</td>
Expand Down Expand Up @@ -381,7 +386,6 @@ import BulkUpdateModal from "../components/BulkUpdateModal.vue"
import BulkDeleteButton from "../components/BulkDeleteButton.vue"
import CSVButton from "../components/CSVButton.vue"
import DeleteButton from "../components/DeleteButton.vue"
import CallbackButton from "../components/CallbackButton.vue"
import DropDownMenu from "../components/DropDownMenu.vue"
import ChangePageSize from "../components/ChangePageSize.vue"
import MediaViewer from "../components/MediaViewer.vue"
Expand Down Expand Up @@ -409,7 +413,8 @@ export default Vue.extend({
showUpdateModal: false,
visibleDropdown: null,
showMediaViewer: false,
mediaViewerConfig: null as MediaViewerConfig
mediaViewerConfig: null as MediaViewerConfig,
showActionDropDown: false,
}
},
components: {
Expand All @@ -420,7 +425,6 @@ export default Vue.extend({
ChangePageSize,
CSVButton,
DeleteButton,
CallbackButton,
DropDownMenu,
MediaViewer,
Pagination,
Expand Down Expand Up @@ -448,6 +452,9 @@ export default Vue.extend({
schema() {
return this.$store.state.schema
},
allActions() {
return this.$store.state.actions
},
rowCount() {
return this.$store.state.rowCount
},
Expand Down Expand Up @@ -579,24 +586,22 @@ export default Vue.extend({
this.showSuccess("Successfully deleted row")
}
},
async executeCallback(rowID) {
if (confirm(`Are you sure you want to run callback for this row?`)) {
console.log("Requesting to run callback!")
async executeAction(action_id) {
if (confirm(`Are you sure you want to run action for this row?`)) {
try {
let response = await this.$store.dispatch("executeCallback", {
let response = await this.$store.dispatch("executeAction", {
tableName: this.tableName,
rowID
rowIDs: this.selectedRows,
actionId: action_id
})
this.showSuccess(`Successfully ran callback and got response: ${response.data}`, 10000)
this.showSuccess(`Successfully ran action and got response: ${response.data}`, 10000)
} catch (error) {
if (error.response.status == 404) {
console.log(error.response.status)
this.$store.commit("updateApiResponseMessage", {
contents: "This table is not configured for callback action",
contents: "This table is not configured for any actions",
type: "error"
})
} else {
console.log(error.response.status)
this.$store.commit("updateApiResponseMessage", {
contents: "Something went wrong",
type: "error"
Expand All @@ -623,6 +628,9 @@ export default Vue.extend({
},
async fetchSchema() {
await this.$store.dispatch("fetchSchema", this.tableName)
},
async fetchActions() {
await this.$store.dispatch("fetchActions", this.tableName)
}
},
watch: {
Expand Down Expand Up @@ -650,7 +658,7 @@ export default Vue.extend({
this.$router.currentRoute.query
)
await Promise.all([this.fetchRows(), this.fetchSchema()])
await Promise.all([this.fetchRows(), this.fetchSchema(), this.fetchActions()])
}
})
</script>
Expand Down Expand Up @@ -727,6 +735,10 @@ div.wrapper {
&:first-child {
margin-left: 0;
}
a.actions-dropdown {
position: relative;
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions admin_ui/vue.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ module.exports = {
port: 3000,
proxy: {
'^/api': {
target: 'http://localhost:8000'
target: 'http://127.0.0.1:8000'
},
'^/public': {
target: 'http://localhost:8000'
target: 'http://127.0.0.1:8000'
}
},
}
Expand Down
5 changes: 3 additions & 2 deletions piccolo_admin/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ async def manager_only(
validators=Validators(post_single=manager_only)
)
)
:param custom_actions: Optional list of custom actions handler function
"""

Expand All @@ -164,7 +165,7 @@ async def manager_only(
hooks: t.Optional[t.List[Hook]] = None
media_storage: t.Optional[t.Sequence[MediaStorage]] = None
validators: t.Optional[Validators] = None
custom_callback: t.Optional[t.Callable] = None
custom_actions: t.Optional[t.List[t.Callable]] = None

def __post_init__(self):
if self.visible_columns and self.exclude_visible_columns:
Expand Down Expand Up @@ -464,7 +465,7 @@ def __init__(
"tags": [f"{table_class._meta.tablename.capitalize()}"]
},
),
callback=table_config.custom_callback,
actions=table_config.custom_actions,
)

private_app.add_api_route(
Expand Down
22 changes: 16 additions & 6 deletions piccolo_admin/example.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
from piccolo_api.session_auth.tables import SessionsBase
from pydantic import BaseModel, validator
from starlette.responses import JSONResponse
from piccolo_api.fastapi.endpoints import TableRowDataSchema

from piccolo_admin.endpoints import FormConfig, TableConfig, create_admin
from piccolo_admin.example_data import (
Expand Down Expand Up @@ -164,6 +165,7 @@ class Genre(int, enum.Enum):
romance = 7
musical = 8

id = BigInt
name = Varchar(length=300)
rating = Real(help_text="The rating on IMDB.")
duration = Interval()
Expand Down Expand Up @@ -259,11 +261,6 @@ async def booking_endpoint(request, data):

return "Booking complete"

async def my_callback_fn(**kwargs) -> JSONResponse:
request_data = kwargs['request_params']
table_name = request_data['table_name']
row_id = request_data['row_id']
return JSONResponse(f"My API received the row_id: {row_id} from table: {table_name}")

TABLE_CLASSES: t.Tuple[t.Type[Table], ...] = (
Director,
Expand All @@ -275,6 +272,19 @@ async def my_callback_fn(**kwargs) -> JSONResponse:
)


# CUSTOM ACTIONS
async def my_custom_action(data: TableRowDataSchema) -> JSONResponse:
row_ids = data.row_ids

# Use the selected row ids to fetch rows from db
movies = await Movie.select().where(Movie.id == row_ids[0])

# Return a JSONResponse which can be displayed back to the frontend
return JSONResponse(f"My API received the row_id: {row_ids}")

async def custom_action_2(data) -> JSONResponse:
return JSONResponse("This is the second action")

movie_config = TableConfig(
table_class=Movie,
visible_columns=[
Expand Down Expand Up @@ -307,7 +317,7 @@ async def my_callback_fn(**kwargs) -> JSONResponse:
media_path=os.path.join(MEDIA_ROOT, "movie_screenshots"),
),
),
custom_callback=my_callback_fn
custom_actions=[my_custom_action, custom_action_2]
)

director_config = TableConfig(
Expand Down

0 comments on commit 87f7968

Please sign in to comment.