3

GitHub - diazoxide/entrefine: Ent-Refine: An Extension for Entgo to Generate a S...

 1 year ago
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.
neoserver,ios ssh client

entrefine

Powerful tool that combines the power of two frameworks, Ent(ORM) and Refine(UI).

cover.png

It simplifies the process of generating CRUDs from Ent definitions with customizable views, fields, actions and search features.

main.png

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.

search.gif

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

Getting ready to use

  1. After configuration regenerate Ent.
  2. Your package.json file is changed so run npm install to get deps.
  3. Check directory of refine application. On src directory you can find entrefine folder with ent resources.
  4. Update your App.ts file
    import 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;
  5. Run npm run dev
  6. 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

  1. First you need to add custom graphql mutation with WhereInput
    # ./mutations.graphql
    myCustomGqlOperation(where: PageWhereInput!): [Page!]
  2. 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.

edges-diagram.png

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

  1. View - Forcing list and show views
  2. ViewOnList
  3. ViewOnShow
  4. ViewOnForm

How to customize?

  1. First create new React Component on custom.tsx (e.g. MyCustomTitle) with ViewProps 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>
    }
  2. Define type of field on schema by entrefine.View annotation

    field.String("title").
         Annotations(
             ...
             entrefine.View("MyCustomTitle"),
             ...
         ),
  3. Regenerate and check

    custom-list-field.png

Custom Badge view

What is a badge?

Badge is a public view of entity on other items edge views. e.g.

img.png

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

logo.svg

Linkedin: https://www.linkedin.com/in/aaron-yor/

Discord: aaron․yordanyan#7556

Phone: +374 98 471111


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK