entrefine is a powerful tool that combines the power of two frameworks, Ent(ORM) and Refine(UI).
It simplifies the process of generating CRUDs from Ent definitions with customizable views, fields, actions and search features.
Live demo: https://demo.entrefine.dev/
Go.dev Package: https://pkg.go.dev/github.com/diazoxide/entrefine
- Generates CRUD operations based on Ent definitions
- Customizable views for each CRUD operation
- Customizable fields for lists, forms, and show views using annotations
- Custom actions for items
- Relational view with nested lists and edges
- Smart search component to find records by every attribute with a custom operator
- Bulk actions on lists
- Uses only a Graphql API with a custom Refine data-provider
- Generates TypeScript types from Ent definitions
- Column filters with customizable operators
- Edges diagram graph view (with gojs or react-force-graph)
- I18n support
- Keycloak Authentication
- Keycloak Authorization
entrefine provides a smart search component to easily find records by any attribute with a custom operator.
The platform uses a Graphql API as the data-provider interface and therefore a GQL extension is mandatory.
Add extension to your Ent framework entc.go
file.
package main
import (
//...
"entgo.io/contrib/entgql"
"github.com/diazoxide/entrefine"
)
func main() {
gqlEx, err := entgql.NewExtension(
// Make sure that EntGql configs are wrapped
EntRefine.EntgqlExtensionOptionsWrapper(
entgql.WithConfigPath("./gqlgen.yml"),
entgql.WithSchemaGenerator(),
entgql.WithSchemaPath("./graphql/ent.graphql"),
entgql.WithWhereInputs(true),
)...,
)
//...
opts := []entc.Option{
entc.Extensions(
// GQL extension is mandatory
gqlEx,
// EntRefine configuration
EntRefine.NewExtension(
EntRefine.WithAppPath(filepath.Join("..", "refine"),
),
),
}
err = entc.Generate(schemaPath, config, opts...)
//...
}
This is important for smart-search component
EntityWhereInput.ApplySearchQuery(q)
package graphql
import (
"ent"
"context"
"github.com/google/uuid"
)
func (r *queryResolver) Companies(
ctx context.Context,
after *ent.Cursor,
first *int,
before *ent.Cursor,
last *int,
orderBy *ent.CompanyOrder,
where *ent.CompanyWhereInput,
q *string, // Added by entrefine
) (*ent.CompanyConnection, error) {
return r.client.Company.Query().Paginate(ctx, after, first, before, last,
ent.WithCompanyOrder(orderBy),
ent.WithCompanyFilter(
where.ApplySearchQuery(q).Filter, // Applying query filter
),
)
}
e.g. EntRefine.FilterOperator("contains")
- ImageField
- MainImageField
- TitleField
- CodeField
- URLField
- RichTextField
- HideOnList
- HideOnShow
- HideOnForm
- FilterOperator
EntRefine.FilterOperator("contains")
- View
- ViewOnList
- ViewOnShow
- ViewOnForm
- Icon (field/entity)
EntRefine.Icon("some-antdesign-icon")
- ListActions (entity)
- NoList
- NoShow
- NoCreate
- NoEdit
- View
- ViewOnList
- ViewOnShow
- ViewOnForm
- Badge
- After configuration regenerate Ent.
- Your package.json file is changed so run
npm install
to get deps. - Check directory of refine application. On src directory you can find
entrefine
folder with ent resources. - Update your
App.ts
fileimport React from "react"; import "@pankod/refine-antd/dist/reset.css"; import {Refine} from "@pankod/refine-core"; import {ErrorComponent, Layout, notificationProvider, ReadyPage,} from "@pankod/refine-antd"; import routerProvider from "@pankod/refine-react-router-v6"; import {GraphQLClient} from "graphql-request"; import {Resources} from "./entrefine/resources"; import dataProvider from "./entrefine/data-provider"; // Provide your graphql query endpoint const client = new GraphQLClient("http://localhost:8081/query"); function App() { return ( <Refine routerProvider={routerProvider} dataProvider={dataProvider(client)} Layout={Layout} ReadyPage={ReadyPage} notificationProvider={notificationProvider} catchAll={<ErrorComponent/>} resources={Resources} /> ); } export default App;
- Run
npm run dev
- Ready
Querying all fields with your defined operator (FilterOperator Annotation) included UUID
function App() {
return (
<Refine
//...
Header={Header}
//...
/>
);
}
import {SearchComponent} from "../../entrefine/search-component";
export const Header: React.FC = () => {
const screens = useBreakpoint();
return (
<AntdHeader style={{
padding: "0 24px",
background: "white",
}}>
<Row align="middle"
style={{
justifyContent: screens.sm ? "space-between" : "end",
}}>
<Col xs={0} sm={12}>
<SearchComponent/>
</Col>
</Row>
</AntdHeader>
);
};
To customize entrefine components you can find ./entrefine/custom.tsx
file on your refine root directory.
Add entity annotation to your schema
EntRefine.ListActions(
EntRefine.ShowAction,
EntRefine.DeleteAction,
EntRefine.EditAction,
EntRefine.Action{
Name: "Custom.MyPrettyButton",
Attrs: map[string]any{},
},
),
// ./entrefine/custom.tsx
//...
export type MyPrettyButtonProps = ButtonProps &
RefineButtonCommonProps &
RefineButtonResourceProps &
RefineButtonSingleProps &
RefineButtonLinkingProps
export const MyPrettyButton: React.FC<MyPrettyButtonProps> = (props) => {
return <Button
icon={<RA.Icons.RadarChartOutlined/>}
onClick={
() => {
alert(props.recordItemId)
}
}></Button>
}
//...
The Edge Graph Diagram is an effective tool for visualizing the relationships between your entities. It presents an interactive representation of the edges, displaying record IDs and their connections to the main record, making it easier to understand and analyze complex data.
Important! By default, the Edge Graph Diagram utilizes GoJS technology. Both GoJS and react-force-graph-2d are available options, allowing you to select the best solution for your needs. However, it's important to note that GoJS is a proprietary library and requires a license key purchased from the GoJS official website for commercial use. On the other hand, react-force-graph-2d is an open-source option.
Customize entrefine extension configs on entc.go file
e.g.
entRefine, err := EntRefine.NewExtension(
...
EntRefine.WithForceGraph2D(
EntRefine.ForceGraph2DOptions{
Enabled: true,
},
),
EntRefine.WithDefaultEdgesDiagram('Diagram.ForceGraph2D'),
...
)
e.g.
entRefine, err := EntRefine.NewExtension(
...
EntRefine.WithGoJs(
EntRefine.GoJSOptions{
Enabled: true,
LicenseKey: "xxxxx-xxxxxx-xxxxx-xxxxx",
},
),
EntRefine.WithDefaultEdgesDiagram('Diagram.GoJS'),
...
)
On entrefine every view of field is customizable for every type of layout.
- View - Forcing list and show views
- ViewOnList
- ViewOnShow
- ViewOnForm
-
First create new React Component on custom.tsx (e.g.
MyCustomTitle
) withViewProps
type props.import {ViewProps} from "./view"; export const MyCustomTitle: React.FC<ViewProps<string>> = ({value}) => { return <RA.Typography.Text copyable={true} style={ {color: "red"} }>{ value }</RA.Typography.Text> }
-
Define type of field on schema by
EntRefine.View
annotationfield.String("title"). Annotations( ... EntRefine.View("MyCustomTitle"), ... ),
Badge is a public view of entity on other items edge views. e.g.
First you need to create new React component like Custom Views.
Then use Badge
annotation to connect it with entity.
Check out the documentation for more information and examples.
Both frameworks (Ent and Refine) are configured as described in documentation.
Linkedin: https://www.linkedin.com/in/aaron-yor/
Discord: aaron․yordanyan#7556
Phone: +374 98 471111