Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AdminJS v7 - feedback, urgent issues, questions, discussions #1473

Open
dziraf opened this issue Apr 18, 2023 · 48 comments
Open

AdminJS v7 - feedback, urgent issues, questions, discussions #1473

dziraf opened this issue Apr 18, 2023 · 48 comments

Comments

@dziraf
Copy link
Contributor

dziraf commented Apr 18, 2023

This is a thread to aggregate all questions/feedback/urgent bugs/discussions related to the recently released version 7.

Feel free to share your ideas or let us know about any issues you're facing related to migration or usage.

What's new in version 7
describes the largest changes in version 7.

Migration Guide will help you migrate your project to version 7.

Demo Application

Demo application also includes our new Themes feature. If you would like to see themes in action, use one of these credentials to sign in:

If you notice that parts of our documentation are outdated or unclear, please share that in this thread as well.

@dziraf dziraf pinned this issue Apr 18, 2023
@ddresch
Copy link
Contributor

ddresch commented Apr 18, 2023

https://www.npmjs.com/package/@adminjs/mongoose the docs are wrong - still showing require statements.

import { Database as MongooseDatabase, Resource as MongooseResource } from '@adminjs/mongoose';

Using this, like in the new example app.

@mszula
Copy link
Contributor

mszula commented Apr 18, 2023

Great work guys!

I'm really in favor of moving to ESM-only but I feel like one thing hasn't been thought through. It's cooperation with NestJS which still uses CJS and has no plans to move to ESM.

nestjs/nest#7021

Do you have any solution for that?

@dziraf
Copy link
Contributor Author

dziraf commented Apr 19, 2023

@mszula until Nest.js moves to ESM or starts dual packaging, you will either have to set up AdminJS express/fastify way or use dynamic imports:

src/app.module.ts

import { Module } from '@nestjs/common';

import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
    import('@adminjs/nestjs').then(({ AdminModule }) =>
      AdminModule.createAdminAsync({
        useFactory: () => ({
          adminJsOptions: { rootPath: '/' },
        }),
      }),
    ),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

tsconfig.json

{
  "compilerOptions": {
    // ...
    "moduleResolution": "nodenext"
  }
}

Instead of import(...).then(...) in app.module.ts you can just set it up Express way in main.ts:

import { NestFactory, HttpAdapterHost } from '@nestjs/core';

import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const AdminJS = await import('adminjs');
  const AdminJSExpress = await import('@adminjs/express');

  const expressApp = app.get(HttpAdapterHost).httpAdapter;
  const admin = new AdminJS.default({});

  expressApp.use(
    admin.options.rootPath,
    AdminJSExpress.default.buildRouter(admin),
  );

  await app.listen(3000);
}
bootstrap();

Note that these changes still rely on you not actually updating to ESM, so you will have to await import(<any adminjs package>) to have it work or just import CJS versions.

As for whether it is possible to still set it up Nest-way - maybe, I don't know. It should be in the interest of NestJS maintainers to proceed with that migration because we cannot impede our own product's development based on their choice of not supporting ESM. Technically ESM projects should be able to import CJS packages, but it doesn't seem to be the case here.

@dziraf
Copy link
Contributor Author

dziraf commented Apr 19, 2023

@ddresch Have you managed to fix your problem? From what I can see you just need to make changes to your tsconfig.json:

"moduleResolution": "nodenext",
"module": "nodenext",
"target": "esnext"

@ddresch
Copy link
Contributor

ddresch commented Apr 19, 2023

Yes – I fixed all my issues now. Thanks for your feedback!

@Aladinndevolpment
Copy link

TypeError: Unknown file extension ".json"

@dziraf
Copy link
Contributor Author

dziraf commented Apr 19, 2023

TypeError: Unknown file extension ".json"

import someJson from './path/to/some.json' assert { type: 'json' }

or use alternatives: https://www.stefanjudis.com/snippets/how-to-import-json-files-in-es-modules-node-js/

@Aladinndevolpment
Copy link

TypeError: Unknown file extension ".json"

Getting this error in adminjs 7 package with nestjs

@dziraf
Copy link
Contributor Author

dziraf commented Apr 19, 2023

Can you show full error log? This could be Nest issue since json imports work fine with every other framework I tried.

@Aladinndevolpment
Copy link

Aladinndevolpment commented Apr 19, 2023

TypeError: Unknown file extension ".json" for E:\application\admin-mode\node_modules\adminjs\lib\locale\de\translation.json

Node version: v16.14.0

@dziraf
Copy link
Contributor Author

dziraf commented Apr 19, 2023

@Aladinndevolpment Looks like type assertions are supported from Node 17+

@mickyarun
Copy link

I am stuck with this issue after upgrading to 7 both themes and typeorm is not detecting though in node_modules it exist
image

@dziraf
Copy link
Contributor Author

dziraf commented Apr 20, 2023

@mickyarun This is the same problem @ddresch had, I think you just have to add:

"moduleResolution": "nodenext",
"module": "nodenext",
"target": "esnext"

to your tsconfig.json

@aeroldb
Copy link

aeroldb commented Apr 23, 2023

@dziraf
is this how I will register the adapter for TypeORM on nestJS?
image

@sumersm7
Copy link

[BUG] iam new to Adminjs idk if this is worth reporting
iam using mongoose when i edit field with population this happend on dark theme its not visible

light theme
image

dark theme
image

@dziraf
Copy link
Contributor Author

dziraf commented Apr 24, 2023

[BUG] iam new to Adminjs idk if this is worth reporting iam using mongoose when i edit field with population this happend on dark theme its not visible

light theme image

dark theme image

Yes, this is a bug. Thank you for reporting, I passed it up.

@dziraf is this how I will register the adapter for TypeORM on nestJS? image

The registerAdapter fragment should be somewhere else, even outside of bootstrap function.

@mszula
Copy link
Contributor

mszula commented Apr 25, 2023

After migration to v7, I always get an error "You have to implement action component for your Action" for custom resource action without component. Something was changed with that, or that's just a bug 😄 ?

test: {
        actionType: 'resource',
        component: false,
        handler: () => {
          return {
            notice: {
              message: 'Success,
              type: 'success',
            },
          };
        },
      },

Edit: I created PR for that 😊

@mickyarun
Copy link

I am creating a bundle in CI/CD pipeline after upgrading to 7, I am getting the following error for the image , any help?
image

@ddresch
Copy link
Contributor

ddresch commented Apr 27, 2023

@mickyarun you need to add the componentLoader instance to the options object of the upload feature instance. Like stated in the error.

@mickyarun
Copy link

mickyarun commented Apr 27, 2023

@ddresch I have added it already, this is happening only if node_env = production
import {componentLoader} from "../../../admin/components.js";
uploadFeature({ componentLoader, provider: {aws: {region: AWS_REGION, bucket: MERCHANT_OFFER_S3_BUCKET_NAME}}, validation: {mimeTypes: ["image/png", "image/jpg", "image/jpeg", "image/svg+xml", "image/webp"]}, uploadPath: (record, filename) =>integrations/${record.id()}/${filename}, properties: { file: "integrationFile", key: "integrationImage", filePath: "integrationFilePath", bucket: MERCHANT_OFFER_S3_BUCKET_NAME } })

My component file

`import {ComponentLoader} from "adminjs";
import path from "path";
import * as url from "url";

const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
export const componentLoader = new ComponentLoader();

export const add = (url: string, componentName: string): string => componentLoader.add(componentName, path.join(__dirname, url));

export const CashbackQRCode = add("components/cashbackqrcode", "CashbackQRCode");`

This is my bundle script

`import {componentLoader} from "../admin/components.js";
import {bundle} from "@adminjs/bundler";

const files = await bundle({
  componentLoader,
  destinationDir: "./.adminjs/"
});`

@SOULPWRD
Copy link

Hi!
Experiencing the very same issue as @mickyarun has just reported.

// imports
// ...
import encryptPassword from '@adminjs/passwords'

const componentLoader = new ComponentLoader()
const resources = Prisma.dmmf.datamodel.models.map((model) => {
  if (model.name === 'User') {
    return {
      resource: { client, model },
      options: {},
      features: [
        encryptPassword({
          properties: {
            encryptedPassword: 'password',
            password: 'newPassword',
          },
          hash,
          componentLoader,
        }),
      ],
    }
  }

  return {
    resource: { client, model },
    options: {},
  }
})

const admin = new AdminJS({ resources, componentLoader })

Screenshot 2023-04-27 at 09 54 26

@mickyarun
Copy link

@dziraf Any help on the above issue, its happening only in production with ADMIN_JS_SKIP_BUNDLE

@dziraf
Copy link
Contributor Author

dziraf commented May 4, 2023

@mickyarun If you use @adminjs/bundler, did you set assetsCDN in AdminJS object?

@SOULPWRD is an entry file generated in .adminjs folder when you start the server?

@damian-balas
Copy link

@dziraf

I hope this message finds you well. I am writing to inquire about the progress on resolving the issue detailed in #1347

While I understand that this bug may be deemed less significant, and potentially tedious to address, I was hoping that you could kindly provide me with an estimated timeframe for a resolution.

As a temporary workaround, we can turn Chrome's autocomplete feature off. However, it would be highly appreciated if an option to address this issue could be implemented as soon as possible.

If it is not possible for you to address this issue within a reasonable timeframe, please let me know if you would welcome a Pull Request from me to resolve the issue.

Thank you for your time and efforts on this matter.

@ariansobczak-rst
Copy link
Contributor

[BUG] iam new to Adminjs idk if this is worth reporting iam using mongoose when i edit field with population this happend on dark theme its not visible

light theme image

dark theme image

Fixed in #1495

@dmitryLagoda
Copy link

Login Page stopped to show errors, e.g in case of incorrect credentials.
You can try to use wrong credentials in the demo app, it's reproducing.
https://demo.adminjs.co/admin/login

@sumersm7
Copy link

[BUG] idk if iam doing something wrong or if its specfic to version 7 or not

i am using mongooes adapter

i have a field name idAuthor Refrence to "user" collection

but when i name it idAuthor it doenst show me dropdown
and when i rename it to author it show dropdown

image
image

is there a way i can keep idAuthor with dropdown

@mickyarun
Copy link

mickyarun commented May 31, 2023

assetsCDN

No I didn't added, all generated files are in .adminjs folder, still I am not able to solve this issue. @dziraf tried adding assetsCDN with all the files components.bundle.js, app.bundle.js,global.bundle.js,design-system.bundle.js still same. The issue is in @adminjs/bundler only, if don't set ADMIN_JS_SKIP_BUNDLE="true" and copy that bundle file to public folder and add the path in assetsCDN , then run with ADMIN_JS_SKIP_BUNDLE="true" its working. so @adminjs/bundler not bundling default plugins

@ankitr-nalkv
Copy link

ankitr-nalkv commented Jun 7, 2023

[BUG] custom actions with component: false, still show a error page to implement component

Have taken the latest v7.0.6
image

The handler associated with the action is called but this page also pops up

@radekdp
Copy link

radekdp commented Jun 29, 2023

Hi,
something is wrong with the nested translations

i18next::translator: missingKey pl translation properties.isActive.true Yes

I have this key in my translations:
image

The column header in the table translates correctly, but the translation in the records is missing:
image

@ismoilh
Copy link

ismoilh commented Jul 4, 2023

Hi I am facing issue with importing @adminjs/nestjs and @adminjs/objection packages I am getting error Cannot find module '@adminjs/objection' or its corresponding type declarations. and yes ive tried to put "moduleResolution": "nodenext",
"module": "nodenext",
"target": "esnext" in tsconfig and pacakges are in node_modules folder someone help me I am not doing anything else Ive just written import its throwing issue thats why no screenshots are passed

@radekdp
Copy link

radekdp commented Jul 12, 2023

Hi,
how can I translate in sidebar navigation.name with avaliable translates in system

image

@golu7679
Copy link

golu7679 commented Jul 18, 2023

Hi I am facing issue with importing @adminjs/nestjs and @adminjs/objection packages I am getting error Cannot find module '@adminjs/objection' or its corresponding type declarations. and yes ive tried to put "moduleResolution": "nodenext", "module": "nodenext", "target": "esnext" in tsconfig and pacakges are in node_modules folder someone help me I am not doing anything else Ive just written import its throwing issue thats why no screenshots are passed

Hey @ismoilh , if you have solved this issue kindly help me. I am having the same issue.

@niyrme
Copy link

niyrme commented Jul 27, 2023

Hi,
something is wrong with the nested translations

i18next::translator: missingKey pl translation properties.isActive.true Yes

I have this key in my translations:
image

The column header in the table translates correctly, but the translation in the records is missing:
image

Having either the property translation or the nested properties (like *.true/*.false) works fine. It only breaks once you have both, and always seems to pick the resource ove the nested ones.

@radekdp
Copy link

radekdp commented Jul 28, 2023

Hi,
something is wrong with the nested translations
i18next::translator: missingKey pl translation properties.isActive.true Yes
I have this key in my translations:
image
The column header in the table translates correctly, but the translation in the records is missing:
image

Having either the property translation or the nested properties (like *.true/*.false) works fine. It only breaks once you have both, and always seems to pick the resource ove the nested ones.

That's right, in an earlier version of AdminJs (6.*) this worked fine

@smiziara
Copy link

smiziara commented Aug 2, 2023

Hi,
something is wrong with the nested translations
i18next::translator: missingKey pl translation properties.isActive.true Yes
I have this key in my translations:
image
The column header in the table translates correctly, but the translation in the records is missing:
image

Having either the property translation or the nested properties (like *.true/*.false) works fine. It only breaks once you have both, and always seems to pick the resource ove the nested ones.

That's right, in an earlier version of AdminJs (6.*) this worked fine

Seems to be because V06 just got the admin.locales and initialized the redux but V07 does a flatten+unflatten on the locales, so this *.true, *.false etc is now broken.

@juanmav
Copy link

juanmav commented Aug 10, 2023

Hi, I wanted to add AdminJs to my expressjs and typescript project using "adminjs": "^7.2.0" with "@adminjs/express": "^6.0.0", "@adminjs/sequelize": "^4.0.0",

and getting the error Cannot find module '@adminjs/sequelize' or its corresponding type declarations.

My index.ts

import express from 'express';
import AdminJs from 'adminjs';
import AdminJsExpress from '@adminjs/express';
import AdminJsSequelize from '@adminjs/sequelize';
import * as allModels from './models';

const host = process.env.HOST ?? 'localhost';
const port = process.env.PORT ? Number(process.env.PORT) : 3000;
const app = express();

AdminJs.registerAdapter({
  Resource: AdminJsSequelize.Resource,
  Database: AdminJsSequelize.Database,
});

const localModel = Object.values(allModels);
localModel.pop(); // Remove Sequelize instance
localModel.pop(); // Remove Sequelize instance

const adminOptions =
  {
    // We pass Category to `resources`
    resources: localModel,
  }

const admin = new AdminJs(adminOptions)
const adminRouter = AdminJsExpress.buildRouter(admin)

app.use(admin.options.rootPath, adminRouter);

app.get('/', (req, res) => {
  res.send({ message: 'Hello API' });
});

app.listen(port, host, () => {
  console.log(`[ ready ] http://${host}:${port}`);
});

My tsconfig.base.json

{
  "compileOnSave": false,
  "compilerOptions": {
    "rootDir": ".",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "importHelpers": true,
    "target": "es2015",
    "module": "esnext",
    "lib": ["es2020", "dom"],
    "skipLibCheck": true,
    "skipDefaultLibCheck": true,
    "baseUrl": ".",
    "paths": {}
  },
  "exclude": ["node_modules", "tmp"]
}

Besides that I tried to use AdminJs version 6 but when NPM tries to resolve the version of @adminjs/express and @admin/sequelize it can not resolve the versions of the dependencies in a straigthforward way.

Any advice how is the best way to proceed?

Thanks in advance
Juan Manuel

@niyrme
Copy link

niyrme commented Aug 22, 2023

Hi, I wanted to add AdminJs to my expressjs and typescript project using "adminjs": "^7.2.0" with "@adminjs/express": "^6.0.0", "@adminjs/sequelize": "^4.0.0",

and getting the error Cannot find module '@adminjs/sequelize' or its corresponding type declarations.

My index.ts

import express from 'express';
import AdminJs from 'adminjs';
import AdminJsExpress from '@adminjs/express';
import AdminJsSequelize from '@adminjs/sequelize';
import * as allModels from './models';

const host = process.env.HOST ?? 'localhost';
const port = process.env.PORT ? Number(process.env.PORT) : 3000;
const app = express();

AdminJs.registerAdapter({
  Resource: AdminJsSequelize.Resource,
  Database: AdminJsSequelize.Database,
});

const localModel = Object.values(allModels);
localModel.pop(); // Remove Sequelize instance
localModel.pop(); // Remove Sequelize instance

const adminOptions =
  {
    // We pass Category to `resources`
    resources: localModel,
  }

const admin = new AdminJs(adminOptions)
const adminRouter = AdminJsExpress.buildRouter(admin)

app.use(admin.options.rootPath, adminRouter);

app.get('/', (req, res) => {
  res.send({ message: 'Hello API' });
});

app.listen(port, host, () => {
  console.log(`[ ready ] http://${host}:${port}`);
});

My tsconfig.base.json

{
  "compileOnSave": false,
  "compilerOptions": {
    "rootDir": ".",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "importHelpers": true,
    "target": "es2015",
    "module": "esnext",
    "lib": ["es2020", "dom"],
    "skipLibCheck": true,
    "skipDefaultLibCheck": true,
    "baseUrl": ".",
    "paths": {}
  },
  "exclude": ["node_modules", "tmp"]
}

Besides that I tried to use AdminJs version 6 but when NPM tries to resolve the version of @adminjs/express and @admin/sequelize it can not resolve the versions of the dependencies in a straigthforward way.

Any advice how is the best way to proceed?

Thanks in advance
Juan Manuel

I had that issue as well first, but setting module and moduleResolution to "NodeNext" in the tsconfig.json seems to resolve that issue

@juanmav
Copy link

juanmav commented Aug 24, 2023

I had that issue as well first, but setting module and moduleResolution to "NodeNext" in the tsconfig.json seems to resolve that issue

That helped! However I had to modify the imports in this "hacky" way

const AdminJs = (await import('adminjs')).default;
const AdminJsExpress = (await import('@adminjs/express')).default;
const AdminJsSequelize = (await import('@adminjs/sequelize')).default;

@rlamorea
Copy link

rlamorea commented Aug 25, 2023

Like @Aladinndevolpment I'm in a catch-22 with the JSON import.

Using express with javascript.

Using nodejs 17.3 I get this when I try to start app.js (this is the app.js from the getting started documentation)

node:internal/errors:464
    ErrorCaptureStackTrace(err);
    ^

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".json" for /Users/rick/projects/rasi/taxservice/node_modules/adminjs/lib/locale/de/translation.json
    at new NodeError (node:internal/errors:371:5)
    at Object.file: (node:internal/modules/esm/get_format:72:15)
    at defaultGetFormat (node:internal/modules/esm/get_format:85:38)
    at defaultLoad (node:internal/modules/esm/load:22:14)
    at ESMLoader.load (node:internal/modules/esm/loader:359:26)
    at ESMLoader.moduleProvider (node:internal/modules/esm/loader:280:58)
    at new ModuleJob (node:internal/modules/esm/module_job:66:26)
    at ESMLoader.#createModuleJob (node:internal/modules/esm/loader:297:17)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:261:34)
    at async ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:81:21) {
  code: 'ERR_UNKNOWN_FILE_EXTENSION'
}

Node.js v17.3.0

If I try to go back to an earlier nodejs (e.g. 16.13) it fails on the assert (which requires 17+).

I'm two pages into the getting started tutorial and completely blocked.

Node v17.3 might not work, but Node v18.17 does!

@qtnx
Copy link

qtnx commented Oct 2, 2023

For those integrating AdminJS with a NestJS monorepo, follow the steps below to configure it properly.

  1. Modify the apps/[appName]/tsconfig.app.json File:
{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "moduleResolution": "nodenext",
    "module": "nodenext",
    "target": "esnext",
    "declaration": false,
    "outDir": "../../dist/apps/[appName]"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "test", "**/*spec.ts"]
}
  1. Disable webpack option in nest-cli.json

Set webpack to false inside compilerOptions
Example, my sub-app named admin

"admin": {
  "type": "application",
  "root": "apps/admin",
  "entryFile": "main",
  "sourceRoot": "apps/admin/src",
  "compilerOptions": {
    "webpack": false,
    "tsConfigPath": "apps/admin/tsconfig.app.json"
  }
}

@SOULPWRD
Copy link

SOULPWRD commented Oct 26, 2023

@mickyarun If you use @adminjs/bundler, did you set assetsCDN in AdminJS object?

@SOULPWRD is an entry file generated in .adminjs folder when you start the server?

Hi, yes it is.

AdminJS.UserComponents = {}

Sorry for a late reply. I was waiting until the version 7 gets a bit stable. Unfortunately, the problem still persists.

@varshiludani
Copy link

Hi @dziraf, I'm facing issues with deleting rows with Hapi and TypeORM. Just created a new project and tried again.

@wtime
Copy link

wtime commented Nov 17, 2023

Hi,
something is wrong with the nested translations
i18next::translator: missingKey pl translation properties.isActive.true Yes
I have this key in my translations:
image
The column header in the table translates correctly, but the translation in the records is missing:
image

Having either the property translation or the nested properties (like *.true/*.false) works fine. It only breaks once you have both, and always seems to pick the resource ove the nested ones.

That's right, in an earlier version of AdminJs (6.*) this worked fine

Seems to be because V06 just got the admin.locales and initialized the redux but V07 does a flatten+unflatten on the locales, so this *.true, *.false etc is now broken.

Hey @dziraf do you have in mind when you will be able to fix this issue?

@AstaDK
Copy link
Contributor

AstaDK commented Dec 21, 2023

Hi, guys cc @dziraf, I faced an issue with filter UI on action list resources.
I'm following the document https://docs.adminjs.co/basics/resource#changing-default-navigation-link to add filter for resource such as my code below:

export const userResource: ResourceWithOptions = {
  resource: UserModel,
  options: {
    id: 'users',
    navigation: {
      icon: 'Users',
    },
    href: ({ h, resource }) => {
      return h.resourceActionUrl({
        resourceId: resource.decorate().id(),
        actionName: 'list',
        search: `?filters.role=User`,
      });
    },

and I faced an issue with the UI. It looks like:

Screenshot 2023-12-21 at 09 05 26

The filter drawer section display below the table (broken UI)
Please let me know any suggestions to fix this issue. Thank guys.

my versions:

  "dependencies": {
    "@adminjs/bundler": "^3.0.0",
    "@adminjs/express": "^6.0.1",
    "@adminjs/mongoose": "^4.0.0",
    "@adminjs/themes": "^1.0.1",
    "mongoose": "^7.4.0",
     "adminjs": "^7.4.2",
    }

@hieupham1203
Copy link

hieupham1203 commented Jan 11, 2024

Hi, I see adminjs/mongoose is using MongooseModel.count, but this function is deprecated. I got error. Please check and update.

image image image

@rushg171
Copy link

Same here! MongooseModel.count() is deprecated! Will it be fixed in the next version?

@jakapurg
Copy link

jakapurg commented Jan 25, 2024

Hey guys, a minor issue I found while adding filters on page navigation.

The following two options act differently.

options: {
                    href: () => undefined,
                    href: undefined
}

The first one hides the resource from the navigation, but it is still acccessible via URL, while the second correctly shows the resource in navigation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests