GitHub - diazoxide/entrefine: Ent-Refine: An Extension for Entgo to Generate a S...
source link: https://github.com/diazoxide/entrefine
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
entrefine
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 and Package Info
Live demo: https://demo.entrefine.dev/
Go.dev Package: https://pkg.go.dev/github.com/diazoxide/entrefine
Roadmap
- 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
- Actions on a list, show, or edit view that trigger a GraphQL mutation.
- Bulk actions on lists
- Relational view with nested lists and edges
- Smart search component to find records by every attribute with a custom operator
- 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)
- Nested create/edit
- Ability to create edges from form
- Ability to edit edges from form
- I18n support
- Keycloak Authentication
- Keycloak Authorization
- Filter by edges
- Sort by edges
- Godoc: provide comprehensive documentation
Smart search
entrefine provides a smart search component to easily find records by any attribute with a custom operator.
Requirements
The platform uses a Graphql API as the data-provider interface and therefore a GQL extension is mandatory.
How to set up?
Extension registration on entc.go
Add extension to your Ent framework entc.go
file.
Example
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...)
//...
}
Then Apply search query to your query resolvers WhereInput
This is important for smart-search component
EntityWhereInput.ApplySearchQuery(q)
Example
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
),
)
}
Configure your ent schemas with annotations
e.g. entrefine.FilterOperator("contains")
Supporting annotations
For Fields
- ImageField
- MainImageField
- TitleField
- CodeField
- URLField
- RichTextField
- HideOnList
- HideOnShow
- HideOnForm
- FilterOperator
entrefine.FilterOperator("contains")
- View
- ViewOnList
- ViewOnShow
- ViewOnForm
For Entities
- Icon (field/entity)
entrefine.Icon("some-antdesign-icon")
- Actions
- NoList
- NoShow
- NoCreate
- NoEdit
- View
- ViewOnList
- ViewOnShow
- ViewOnForm
- Badge
Getting ready to use
- 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
Search Component <SearchComponent/>
How it works?
Querying all fields with your defined operator (FilterOperator Annotation) included UUID
Example
Root App
function App() {
return (
<Refine
//...
Header={Header}
//...
/>
);
}
Header component
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>
);
};
Customization
File custom.tsx
To customize entrefine components you can find ./entrefine/custom.tsx
file on your refine root directory.
Custom Actions
Add entity annotation to your schema
Annotation Example
entrefine.Actions(
entrefine.ShowAction,
entrefine.DeleteAction,
entrefine.EditAction,
entrefine.Action{
Operation: "myCustomGqlOperation",
Fields: []string{
"id", "title"
},
Label: "Do something",
FailMessage: "Something bad happened",
SuccessMessage: "${ resp.data.length } Pages processed",
OnList: true,
OnShow: true,
Bulk: true,
Icon: "RA.Icons.RadarChartOutlined",
},
),
Implementation Example
- First you need to add custom graphql mutation with
WhereInput
# ./mutations.graphql myCustomGqlOperation(where: PageWhereInput!): [Page!]
- Then let's write mutation resolver
func (r *mutationResolver) MyCustomGqlOperation(ctx context.Context, where generated.PageWhereInput) ([]*generated.Page, error) { w, err := where.P() p, err := r.client.Page.Query().Where(w).All(ctx) err = someCustomAction(p...) if err != nil { return nil, err } return p, nil }
Edges diagram graph view
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.
How to enable
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.
How to switch GoJS to react-force-graph-2d
Customize entrefine extension configs on entc.go file
entRefine, err := entrefine.NewExtension(
...
entrefine.WithForceGraph2D(
entrefine.ForceGraph2DOptions{
Enabled: true,
},
),
entrefine.WithDefaultEdgesDiagram('Diagram.ForceGraph2D'),
...
)
GoJS license and configuration
entRefine, err := entrefine.NewExtension(
...
entrefine.WithGoJs(
entrefine.GoJSOptions{
Enabled: true,
LicenseKey: "xxxxx-xxxxxx-xxxxx-xxxxx",
},
),
entrefine.WithDefaultEdgesDiagram('Diagram.GoJS'),
...
)
Custom views
On entrefine every view of field is customizable for every type of layout.
Special annotations
- View - Forcing list and show views
- ViewOnList
- ViewOnShow
- ViewOnForm
How to customize?
-
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"), ... ),
Custom Badge view
What is a badge?
Badge is a public view of entity on other items edge views. e.g.
Badge customization
First you need to create new React component like Custom Views.
Then use Badge
annotation to connect it with entity.
Example
Check out the documentation for more information and examples.
Both frameworks (Ent and Refine) are configured as described in documentation.
Contacts
Linkedin: https://www.linkedin.com/in/aaron-yor/
Discord: aaron․yordanyan#7556
Phone: +374 98 471111
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK