Giter Site home page Giter Site logo

conda-incubator / conda-store-ui Goto Github PK

View Code? Open in Web Editor NEW
13.0 13.0 18.0 10.34 MB

conda-store-ui is a frontend for conda-store powered by react

Home Page: https://conda-incubator.github.io/conda-store-ui/

License: BSD 3-Clause "New" or "Revised" License

JavaScript 2.34% TypeScript 92.45% CSS 0.07% Dockerfile 0.10% Python 4.75% Shell 0.02% MDX 0.15% Smarty 0.12%

conda-store-ui's People

Contributors

anirrudh avatar costrouc avatar dcmcand avatar gabalafou avatar iameskild avatar jonzeper avatar jujogi avatar kcpevey avatar nkaretnikov avatar ostojics avatar pavithraes avatar pierrotsmnrd avatar seohyun-a avatar steff456 avatar tatiana45 avatar telamonian avatar trallard avatar ximenacor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

conda-store-ui's Issues

List of packages names is incomplete

When I want to add a package named "dask", I should get the following list of packages available :

"airflow-with-dask"
"dagster-dask"
"dagster_dask"
"dask"
"dask-bigquery"
"dask-cloudprovider"
"dask-core"
"dask-ctl"
"dask-cuda"
"dask-distance"
"dask-drmaa"
"dask-ec2"
"dask-funk"
"dask-gateway"
"dask-gateway-kerberos"
"dask-gateway-server"
"dask-gateway-server-jobqueue"
"dask-gateway-server-kerberos"
"dask-gateway-server-kubernetes"
"dask-gateway-server-local"
"dask-gateway-server-yarn"
"dask-geomodeling"
"dask-geopandas"
"dask-glm"
"dask_groupby"
"dask-histogram"
"dask-image"
"dask-imread"
"dask-jobqueue"
"dask-kubernetes"
"dask-labextension"
"dask_labextension"
"dask-memusage"
"dask-ml"
"dask-mongo"
"dask-mpi"
"dask-ms"
"dask-ndfilters"
"dask-ndfourier"
"dask-ndmeasure"
"dask-ndmorph"
"dask-searchcv"
"dask-snowflake"
"dask-sphinx-theme"
"dask-sql"
"dask-tensorflow"
"dask_traj"
"dask-xgboost"
"dask-yarn"
"ibis-dask"
"label-maker-dask"
"modin-dask"
"nd2-dask"
"pandera-dask"
"pandera-modin-dask"
"pangeo-dask"
"prefect-dask"
"qhub-dask"
"qhub-dask-meta"
"resource_backed_dask_array"
"tethys_dask_scheduler"
"tpot-dask"
"unidist-dask"

The autocomplete list only shows "airflow-with-dask", i.e. the first one.
The API endpoints returns the list of packages and all their versions, so you need to use the pagination to crawl through all the pages, and retrieve the full list of package names.

Also, sort in a way that if a package name is the exact input of the user, this package appears first. Here, "dask" should appear first, then "airflow-with-dask", "dagster-dask", etc.

Multiple createApi instances for the same API

Currently, in the project, we have 2 createApi definitions for the same API we are talking to. That's considered an anti-pattern when using RTK Query.
We should refactor those parts of the code and change the baseUrl to http://localhost:5000/conda-store/ and all endpoints should be built from there. I apologize for not seeing this earlier.
Redux docs

I know that we have different URLs like /conda-store/api/v1 and /conda-store/login, but we are talking to the same server and should have one createApi definition per server.

Show the complete list of namespaces and environments

The API offers an API endpoint that lists the permissions of the user :
http://localhost:5000/conda-store/api/v1/permission/ yields a result similar to :

{
  "status": "ok",
  "data": {
    "authenticated": true,
    "primary_namespace": "admin",
    "entity_permissions": {
      "default/*": [
        "environment::read",
        "namespace::read"
      ],
      "filesystem/*": [
        "environment::read",
        "namespace::read"
      ],
      "*/*": [
        "build::delete",
        "environment::delete",
        "environment::read",
        "environment::update",
        "environment:create",
        "namespace::create",
        "namespace::delete",
        "namespace::read"
      ]
    },
    "entity_roles": {
      "default/*": [
        "viewer"
      ],
      "filesystem/*": [
        "viewer"
      ],
      "*/*": [
        "admin"
      ]
    },
    "expiration": "2022-09-03T13:33:27+00:00"
  },
  "message": null
}

Here we can see that I can read and write in environments filesystem and default, but only filesystem appears in the UI.

Create environment : full feature

Goal :

Allowing the user to create a new environment, in a given namespace

Design :

conda-store-UI-create

Behavior :

  • Clicking on the + button at the right of a namespace, opens a new empty tab to create a new env in that namespace

  • the field to enter the new env name has a placeholder text "Environment name"

  • The field to enter the description is shown as a multiline text box, the other usual components (Build, Status ...) are hidden

  • The Specification box only contains the "Requested packages" and "Channels" boxes

    • The "Requested packages" doesn't show column "installed version".
    • The list of requested packages should be empty, the screenshot shows Python 3.8 only for example purpose
    • The list of channels must be empty, the screenshot shows conda-forge only for example purpose
  • Clicking on Create will call the API to create the env, and update the UI to display the env as a classic, read-only mode

  • Clicking on the switch "Switch to YAML Editor" will turn the UI into :
    Capture d’écran 2022-08-15 à 14 01 59

    • "Switch to YAML Editor" becomes "Switch to standard view"
    • the shown YAML text must reflect what the user entered in the standard view (same channels and packages), and any modification in the YAML must be applied to the standard view when the user switches back.
  • the YAML editor we chose is : https://www.npmjs.com/package/@uiw/react-codemirror

  • In case of error when creating the env, the error message returned by the API will be shown like this :
    conda-store-ui-create-error

API and data

  • the API endpoint to use is POST /conda-store/api/v1/specification/
  • It takes as a body a JSON dict with two keys, specification and namespace
    • namespace is the name of the namespace in which adding the env
    • specification is the YAML representing the env, with its newline characters replaced by "\n".
      example : if YAML is :
channels:
- conda-forge
dependencies:
- python ==3.9
- flask
- pandas
- pip:
  - nothing
- ipykernel
description: test description
name: python-flask-env-test
prefix: null

the expected JSON to add this env to a namespace named "test-api" is :

{
  "specification": "channels:\n- conda-forge\ndependencies:\n- python ==3.9\n- flask\n- pandas\n- pip:\n  - nothing\n- ipykernel\ndescription: test description\nname: python-flask-env-test\nprefix: null",
  "namespace": "test-api"
}

Other :

Split this main component into sub-components as necessary.

Environment metadata block - read only

Goal :

Have the block to display metadata of an env - in read only mode.

Figma design

Capture d’écran 2022-07-14 à 14 12 42

CAVEAT : The build hash to display with the build date is not ready yet (see issue conda-incubator/conda-store#338 )

  • In the list of builds, the different statuses of env builds can be :
    Capture d’écran 2022-07-14 à 14 13 07

Behavior

  • The list of builds must be shown from the most recent to the oldest (see details in the API section below)

  • The list of builds is obtained by the API, which yields paginated results. Expect the list of builds to be loaded in multiple steps : first batch (page 1 of API results), then when the users scrolls to the bottom of the list, page 2 is loaded and displayed.

  • In the Status section, and in the list of builds, the status will display "Queued", "Available", "Building" or "Failed". If the status is "Building", a spinning indicator will be displayed.

  • For later : Picking a version of an env will update the specification block.

API and data

  • The description part is not available in the API yet. ( see issue conda-incubator/conda-store#339 )

  • The list of builds can be obtained with one endpoint in two ways :

    • /api/v1/build/?environment_id=[ENV_ID]
    • /api/v1/build/?name=[ENV_NAME]

Pick the way that is the most convenient. This endpoint yields a result similar to :

{
  "status": "ok",
  "data": [
    {
      "id": 2,
      "environment_id": 2,
      "specification": null,
      "packages": null,
      "status": "COMPLETED",
      "size": 315875085,
      "scheduled_on": "2022-07-14T12:38:42.932219",
      "started_on": "2022-07-14T12:38:44.116409",
      "ended_on": "2022-07-14T12:39:48.185573",
      "build_artifacts": null
    },
    {
      "id": 3,
      "environment_id": 2,
      "specification": null,
      "packages": null,
      "status": "COMPLETED",
      "size": 315875075,
      "scheduled_on": "2022-07-14T12:40:38.095584",
      "started_on": "2022-07-14T12:40:38.330526",
      "ended_on": "2022-07-14T12:41:33.092302",
      "build_artifacts": null
    }
  ],
  "message": null,
  "page": 1,
  "size": 100,
  "count": 2
}
  • The different values of the status field are : "QUEUED", "BUILDING", "COMPLETED", "FAILED"
  • This is a paginated result, expect adding a ?page= parameter to the API URL
  • The results are ordered by ID ascending, and issue is going to be open to allow sorting by various fields.

Other :
Split this main component into sub-components as necessary.

List of namespaces and environments : connect to the API

In issue #21 we handle the list of namespaces and environments.

So far, this component uses mockup data.
Now that we are able to interact with the API, we can connect it and have the actual list of namespaces and environments for the given user.

All the informations about the API are in the original issue.

Package versions sorting

For the moment, the autocompletion of the package versions make the list of versions appear sorted in an alphabetical way.
This leads to have a list like :

1.9.0
1.22.0
1.1.2

Because 2 is considered before 9.

To sort the versions, the UI needs to perform some operations to split the parts of the version.
Following the previous example, by splitting on the dot :

1.9.0.     ➞  Major 1, minor 9, revision 0
1.22.0     ➞  Major 1, minor 22, revision 0 
1.1.2      ➞  Major 1, minor 1, revision 2 

And then, if we order by Major descending, minor descending, and revision descending, we get the right sort :

1.22.0     ➞  Major 1, minor 22, revision 0 
1.9.0.     ➞  Major 1, minor 9, revision 0
1.1.2      ➞  Major 1, minor 1, revision 2 

Unfortunately, not all the versions are following this pattern.
Some version numbers have 4 dots, or underscores, or even texts.

Recipe :

So, here is a recipe to sort the version numbers (The version numbers will appear unmodified in the list, use this only to perform the sort) :

  • if the version number starts with a "v" (like "v1.2.3"), remove it
  • split all the version numbers on the dots and underscores.
  • convert each value to integers. If there are any non-numeric characters, remove them

in the end, for each version number, you'll have something like a list of integers. Consider the first one as the Major, the second one as the minor, etc, and use this list to sort the versions accordingly.

Example

Example with Numpy's versions :
Considers the list of versions of numpy :

"1.10.4", "1.11.0", "1.11.1", "1.11.2", "1.11.3", "1.12.0", ... "1.22.0", "1.22.1", "1.22.2", "1.22.3", "1.22.4", "1.23.0", "1.23.1", "1.23.2", "1.23.3", "1.7.2", "1.8.2", "1.9.3"

By applying the above recipy, we get the following list of integers for each version (not sorted yet)

"1.10.4"	➞ [1, 10, 4]
"1.11.0"	➞ [1, 11, 0]
"1.11.1"	➞ [1, 11, 1]
"1.11.2"	➞ [1, 11, 2]
"1.11.3"	➞ [1, 11, 3]
"1.12.0"	➞ [1, 12, 0]
...
"1.20.0"	➞ [1, 20, 0]
...
"1.20.3"	➞ [1, 20, 3]
"1.21.0"	➞ [1, 21, 0]
"1.21.1"	➞ [1, 21, 1]
...
"1.21.6"	➞ [1, 21, 6]
"1.22.0"	➞ [1, 22, 0]
...
"1.22.4"	➞ [1, 22, 4]
"1.23.0"	➞ [1, 23, 0]
"1.23.1"	➞ [1, 23, 1]
"1.23.2"	➞ [1, 23, 2]
"1.23.3"	➞ [1, 23, 3]
"1.7.2"		➞ [1 ,7, 2]
"1.8.2"		➞ [1 ,8, 2]
"1.9.3"		➞ [1 ,9, 3]

Now, by sorting the versions according to their list of integers, in a decreasing way, we'll get the list sorted as expected :
['1.23.3', '1.23.2', '1.23.1', '1.23.0', '1.22.4', '1.22.3', '1.22.2', '1.22.1', '1.22.0', '1.21.6', '1.21.5', '1.21.4', '1.21.3', '1.21.2', '1.21.1', '1.21.0', '1.20.3', '1.20.2', '1.20.1', '1.20.0', '1.19.5', '1.19.4', '1.19.2', '1.19.1', '1.19.0', '1.18.5', '1.18.4', '1.18.1', '1.17.5', '1.17.3', '1.17.2', '1.17.1', '1.17.0', '1.16.6', '1.16.5', '1.16.4', '1.16.3', '1.16.2', '1.16.1', '1.16.0', '1.15.4', '1.15.3', '1.15.2', '1.15.1', '1.15.0', '1.14.6', '1.14.5', '1.14.4', '1.14.3', '1.14.2', '1.14.1', '1.14.0', '1.13.3', '1.13.2', '1.13.1', '1.13.0', '1.12.1', '1.12.0', '1.11.3', '1.11.2', '1.11.1', '1.11.0', '1.10.4', '1.9.3', '1.8.2', '1.7.2']

add the necessary part for API Fetching

The UI will heavily rely on Conda Store API.
@ostojics I'll put you up to speed with how to run Conda Store, and how to use the API.

The API fetching part will be closely related to the Redux Data Model part (issue #19)

List of 'Packages installed as dependencies' - edit mode

Goal :

have a react component to display a list of packages installed as dependencies and "promoting" a dependency package as a required package.

Figma design

Capture d’écran 2022-06-21 à 12 53 33

  • the "arrow up" button on the right is the "promote as required" button

Concepts :

same as in issue #8

Differences from the Figma design :

  • Don't display the "Version" before the version number
  • Display the package name as it is returned by the API (no uppercased first letter modification)

Behavior

  • The box has a maximum height and overflow content scrolls. Expect this height to be a parameter.
  • Clicking on the top arrow in the header collapses/expands the box.
  • Click on the promote button :
    • Removes the row from the component
    • Add the corresponding package in the "Requested packages" component
    • We'll need to keep track of this change and reflect it when the user clicks on the final "Create" button to build the environment. I assume this will be handled from in Redux.

API and data

Check the "API and data" section in issue #8.
We don't want to load all the packages at first, page after page. We want the list in the component to automatically call the API (for the moment, just mock that up) when the user scrolls to the bottom of the list, and then the component updates its content after received the result.

Other :
Split this main component into sub-components as necessary.

In the end, this component is very similar to it read-only version, only showing the promote button and being linked to a Requested packages component.

"Logs and artifacts" block

Goal :

Have the block listing the artifacts for the given build

Figma design

Capture d’écran 2022-07-15 à 07 03 29

API and data

Each link will point to a different API endpoint :

  • YAML file : api/v1/build/{build_id}/yaml/
  • lockfile : api/v1/build/{build_id}/lockfile/
  • archive : api/v1/build/{build_id}/archive/
  • logs : api/v1/build/{build_id}/logs/

Other :
Split this main component into sub-components as necessary.

Version constraint appears when creating an env

Here is the reproduction scenario :

  • I click on the + to create an environment

  • I click on "add package" to add a package row

  • First bug : the layout is broken. The shown header row shown is correct ("Name" and "Version Constraint"), but the package row seems to show 3 columns ("Enter Package", an empty space, and the trash bin icon)
    Capture d’écran 2022-09-23 à 11 24 39

  • I enter "numpy"

  • Second bug : a version number appears.

I assume this number is an "installed version", but it doesn't make sense. We're creating an environment, there shouldn't be any installed version.

Capture d’écran 2022-09-23 à 11 21 20

List of Artifacts : rework

I have noticed that the ArtifactsList takes a list of link as parameter.

We expect the ArtifactsList to take a build id as parameter, and it builds the list of links from within. The list of links is static, predefined, and depends only on the build id to build the exact URLs.

So, instead of having something like :

const artifactsList = [
  {
    name: "Link to lockfile",
    route: "/api/v1/build/1/lockfile/"
  },
  {
    name: "Link to yml file",
    route: "/api/v1/build/1/yaml/"
  },
  {
    name: "Link to archive",
    route: "/api/v1/build/1/archive/"
  },
  {
    name: "Conda Env 1 log",
    route: "/api/v1/build/1/logs"
  }
];

// (...)

export const Primary: ComponentStory<typeof ArtifactsList> = () => (
  <ArtifactsList artifacts={artifactsList} />
);

we expect something like this, for a similar result :

const build_id = 42;

export const Primary: ComponentStory<typeof ArtifactsList> = () => (
  <ArtifactsList build_id={build_id} />
);

Also, the links to the artifacts must point to the conda-store API backend. For far, they point to the local webapp, which leads to 404.

Docstrings on all components

Each component requires to have docstrings to document its behavior and also populate the Storybook view :

image (1)

@telamonian left TODO at everyplace where docstrings are missing.

[discussion] How to represent the active build

In this issue on Conda Store, we discussed the best way to represent the "build numbers", which eventually became the build date and a hash, like :

May 31, 2022 - 17:00 (a1b2c3)
May 27, 2022 - 16:42 (f9e8d7)

In the figma design (last version), we display the build date and hash like this :
Capture d’écran 2022-06-25 à 08 17 50

Now the question is : How do we represent the active build ?

My suggestion : The dropdown list of builds could display the builds like this :

May 31, 2022 - 17:00 (a1b2c3) - active
May 27, 2022 - 16:42 (f9e8d7)
May 21, 2022 - 09:13 (d4e5f6)

List of 'Packages installed as dependencies' - read only mode

Goal :

have a react component to display a list of packages installed as dependencies (read-only)

Figma design

Capture_decran_2022-06-15_a_10 40 08

Concepts :

  • a 'package installed a dependency' has a name, and a version
  • the name of a package has usually around 10 characters, but can go up to 30
  • A constraint states which version of a the package was installed. It is a standard version number like : 12.3.4, 3.2.1, ...
  • the list of names and versions will be given by the API. These informations are shared to give a sense of what to expect and size the components accordingly.

Differences from the Figma design :

  • Don't display the "Version" before the version number
  • Display the package name as it is returned by the API (no uppercased first letter modification)

Behavior

  • The box has a maximum height and overflow content scrolls. Expect this height to be a parameter.
  • Clicking on the arrow collapses/expand the box.

API and data

The API endpoint is like : api/v1/build/<build_id>/packages and the result data are paginated.

Example of paginated data for an env :

To get the first page of result, we will call the API like : api/v1/build/<build_id>/packages or equivalent api/v1/build/<build_id>/packages?page=1.
It yields a result similar to :

{
   "status":"ok",
   "data":[
      {
         "id":3685,
         "channel":{
            "id":2,
            "name":"https://conda.anaconda.org/conda-forge",
            "last_update":null
         },
         "build":"pyhd8ed1ab_0",
         "license":"Apache-2.0",
         "sha256":"4da0fe03babc950532513e9165dbc337a663880352392f496992776608dd77ca",
         "name":"asttokens",
         "version":"2.0.5",
         "summary":"The asttokens module annotates Python abstract syntax trees (ASTs) with the positions of tokens and text in the source code that generated them."
      },
      {
         "id":3673,
         "channel":{
            "id":2,
            "name":"https://conda.anaconda.org/conda-forge",
            "last_update":null
         },
         "build":"pyh9f0ad1d_0",
         "license":"BSD-3-Clause",
         "sha256":"ee62d6434090c1327a48551734e06bd10e65a64ef7f3b6e68719500dab0e42b9",
         "name":"backcall",
         "version":"0.2.0",
         "summary":"Specifications for callback functions passed in to an API"
      },
( ...  97 other packages here )
      {
         "id":3695,
         "channel":{
            "id":2,
            "name":"https://conda.anaconda.org/conda-forge",
            "last_update":null
         },
         "build":"pyh9f0ad1d_2",
         "license":"ISC",
         "sha256":"04eef875d461732ef22cd19bf2c989c40e73b5da625bf6a6b82ddae200e90e56",
         "name":"pexpect",
         "version":"4.8.0",
         "summary":"Pexpect makes Python a better tool for controlling other applications."
      }
   ],
   "message":null,
   "page":1,
   "size":100,
   "count":155
}
  • The count field indicates how many results there are. Here, 155. We have 100 result per page, so to get next page, we'll have to call the api again like api/v1/build/<build_id>/packages?page=2 and use the result again to update the list of the component.
  • The relevant data in the results to display are name and version

@ostojics :

  • You'll have to find a way to mockup this pagination thing before we connect to the API.
  • The API returns 100 result per page but it can be changed using the parameter size like : api/v1/build/<build_id>/packages?page=1&size=10. Expect the size parameter to change, pages won't always have 100 results.
  • We don't want to load all the packages at first, page after page. We want the list in the component to automatically call the API (for the moment, just mock that up) when the user scrolls to the bottom of the list, and then the component updates its content after received the result.
  • Expect to show a spinner in the component during load time.

Other :
Split this main component into sub-components as necessary.

.env file : summary of what is needed so far

This issue's goal is to summarize what needs to be sent to a .env file, as seen here and there in the project :

  • URL to the API ( as seen here)
  • AUTH_METHOD=cookie ( as seen in issue #53 )
  • While the login page is being redone, we're using an API token to interact with the API. Let's put it in the .env too.

Main navigation structure - with read-only environment details

Goal :

Have the main navigation structure of the app, with list of environments on the left, and details of an env on the right.
For this step, the details of the environment will be displayed in read-only mode.

Figma design

Capture d’écran 2022-07-14 à 13 24 04

Behavior

  • Clicking on an environment on the left panel opens a new tab in the main area.
  • In case multiple tabs are open : When switching from one tab to another, the focus is put on the corresponding environment in the left panel.
  • Clicking on the close button (x) at the right of a tab, closes the tab.

Related components :

  • The left pane is the list of environments and namespaces as listed in issue ( #21 )
  • Each tab display the page of environment details in read only mode ( #30 )

API and data

  • To display the environment page in a tab, you'll need an environment id. This is will be given by the selected environment in the left pane.

Other :
Split this main component into sub-components as necessary.

Environment description : retrieve from API and display it

The environment description is now available in the backend.
Caveat : You'll need the latest version of conda-store because I had a PR merged to provide a fix.

When calling GET api/v1/environment/[NAMESPACE]/[ENV_NAME]/, for exampleGET api/v1/environment/default/example-env/, the returned payload now contains the description :

{
  "status": "ok",
  "data": {
    "id": 2,
    "namespace": {
      "id": 1,
      "name": "default"
    },
    "name": "example-env",
    "current_build_id": 2,
    "current_build": null,
    "description": "This is an example of conda-store environment"
  },
  "message": null
} 

Use this to display the environment's description in the UI, both read-only and edit mode.

After creating an environment, the layout is not updated properly

I created an environment, and clicked "Create".

The layout is switched back to editable mode, but multiple problems appear :

  • the environment metadata doesn't show the "build" and "status" lines
  • the description field is left editable
  • the requested packages is empty
  • the channels list is empty (you need to expand it to see it) whereas it should display the list of channels
  • the tab name is still "create environment" whereas it should display the env name
  • the list of environments on the left panel is not updated

though, refreshing the page displays the expected data.

Capture d’écran 2022-09-23 à 11 30 32

Define a Data Model for Redux

We need to define a data model in Redux to store the changes made on the UI. We can see that as the differences between the UI and the data from the API.
The way we store these data can be JSON or can be more simple and less verbose, like YAML. It seems that's what we're going to use.

@telamonian I assign this issue to you. Add here all the details, blockers and other points that might be relevant for @ostojics making the components, or me for the API.

YAML Editor : technical choice

Goal :

Have an overview of the available tools to render YAML in a react UI.

Figma design

Capture d’écran 2022-08-01 à 16 24 25

CAVEAT : the goal of this issue is to make a technical choice, not to render this component

Requirements

  • The tool must be able to render a YAML text with syntax highlighting
  • The tool must be compatible with a JupyterLab extension ( @telamonian will give feedback on that )

Excepted result

  • A list of the 3 or 4 best solutions for this, before Max reviews. Then we'll pick one.
  • For each solution, please provide a links to github repo / docs / etc
  • The react text editor "Monaco" is already excluded.

Authentication pages (webapp only)

Goal

Authenticate the user from within the UI

Context

To display accurate and comprehensive results, we need to interact with the API in an authenticated way.

The UI we're building has 2 destinations :

  • a standalone webapp to interact with Conda Store
  • a JupyterLab Extension

From within the standalone webapp, we need UI components to authenticate the user, as it is already the case in the current UI.
(From within the JupyterLab Extension, the auth will be done via a different mechanism, more about that in another issue later)

Logging-in with the API will set a cookie that will have to be reused for all the call to the API.

Requirements

We don't have material in the figma design to represent what is expected, but this is a pretty simple piece of design.
Also, this will surely evolve in the future with a coat of styling. What matters is that the feature itself works.

  • add a button on the top right corner of the left menu.
    This button can be enabled/shown or disabled/hidden using a an env variable (I suggest AUTH_METHOD=cookie )
    Capture d’écran 2022-08-08 à 07 28 57

  • Clicking on this button will lead to a /login with a UI similar to what we currently have.
    This is a simple POST form with two fields username and password, posting to API endpoint /login
    Capture d’écran 2022-08-08 à 07 36 11

  • If auth is invalid, display an error message
    Capture d’écran 2022-08-08 à 07 49 11

  • if auth is valid, redirect to the main page. We expect the results to be updated now that the user is authenticated.

JupyterLab Extension

This issue will contain all the necessary discussion around making the UI a JupyterLab extension.

[discussion] Raw yaml editor

There's a need for a raw yaml editor to let the power users add pip packages or packages hosted on git repos.

My suggestion :

  • add a button at the top left corner of the Specification box, to switch to the YAML editor
  • In this mode, show a YAML composer button to switch back to previous mode
  • Each view would represent the exact same data for the channels and the requested packages (that's not the case in the following images, they're for illustration purpose)

composer

editor

Add a package : autocomplete the package versions

The autocompletion of the packages names is done.
Now, let's make the autocompletion for the packages versions

The API endpoint to list all the versions for a packages is :
http://localhost:5000/conda-store/api/v1/package/?search=[PACKAGE_NAME]&exact=true&distinct_on=version&page=1&order=desc&sort_by=version

For example, to list all the versions of numpy :
http://localhost:5000/conda-store/api/v1/package/?search=numpy&exact=true&distinct_on=version&page=1&order=desc&sort_by=version

It yields a result similar to :

{
  "status": "ok",
  "data": [
    {
      "id": 687061,
      "channel": {
        "id": 3,
        "name": "https://repo.anaconda.com/pkgs/main",
        "last_update": null
      },
      "build": "py35_nomklh11ed3e2_3",
      "license": "BSD 3-Clause",
      "sha256": "2808b44e32427033eaf71c99fc84f193430b38968df01aa14d14441188faa143",
      "name": "numpy",
      "version": "1.9.3",
      "summary": "Array processing for numbers, strings, records, and objects."
    },
    {
      "id": 534297,
      "channel": {
        "id": 2,
        "name": "https://conda.anaconda.org/conda-forge",
        "last_update": null
      },
      "build": "py36_blas_openblas_201",
      "license": "BSD 3-Clause",
      "sha256": "c1631c0070c2be09d2708982ec52ea53a502b41ba416d14873396f75f86e7ed0",
      "name": "numpy",
      "version": "1.8.2",
      "summary": "The fundamental package for scientific computing with Python."
    },
    {
      "id": 411923,
      "channel": {
        "id": 2,
        "name": "https://conda.anaconda.org/conda-forge",
        "last_update": null
      },
      "build": "py34_blas_openblas_202",
      "license": "BSD 3-Clause",
      "sha256": "8af26b828d0d65b65c1233f91dbb637891b0a98f7de9f5e2671b9cdf2f87fa0e",
      "name": "numpy",
      "version": "1.7.2",
      "summary": "The fundamental package for scientific computing with Python."
    },
...
    {
      "id": 420357,
      "channel": {
        "id": 2,
        "name": "https://conda.anaconda.org/conda-forge",
        "last_update": null
      },
      "build": "py35_blas_openblas_202",
      "license": "BSD 3-Clause",
      "sha256": "8e34f74fb296c3d4b139765df9a105d7eb9e43af24ed38447f6e19144f4563d3",
      "name": "numpy",
      "version": "1.11.2",
      "summary": "The fundamental package for scientific computing with Python."
    },
    {
      "id": 200635,
      "channel": {
        "id": 2,
        "name": "https://conda.anaconda.org/conda-forge",
        "last_update": null
      },
      "build": "py27_blas_openblas_200",
      "license": "BSD 3-Clause",
      "sha256": "094f06be39a4d768f5da112dc5a474791d9e277afede6923d4108d0a9f08ed16",
      "name": "numpy",
      "version": "1.11.1",
      "summary": "The fundamental package for scientific computing with Python."
    },
    {
      "id": 379861,
      "channel": {
        "id": 2,
        "name": "https://conda.anaconda.org/conda-forge",
        "last_update": null
      },
      "build": "py35_blas_openblas_201",
      "license": "BSD 3-Clause",
      "sha256": "7915ff7bf87c2b1e05b7f7e6f64cd6900241ae09b7156e533d9815c72ebe0151",
      "name": "numpy",
      "version": "1.11.0",
      "summary": "The fundamental package for scientific computing with Python."
    },
    {
      "id": 239286,
      "channel": {
        "id": 2,
        "name": "https://conda.anaconda.org/conda-forge",
        "last_update": null
      },
      "build": "py35_blas_openblas_203",
      "license": "BSD 3-Clause",
      "sha256": "25368dd096b8c2e241f64b7102bf4f176735927f0fda261c10468c865a7d7286",
      "name": "numpy",
      "version": "1.10.4",
      "summary": "The fundamental package for scientific computing with Python."
    }
  ],
  "message": null,
  "page": 1,
  "size": 100,
  "count": 66
}

CAVEAT : the given URL orders the versions but considers them as strings, so they are not ordered numerically. Hence, a version number like 1.9.0 is considered more recent than 1.11.0 because 9 > 1.

But we want to present the versions ordered from the most recent version to the oldest.
This should be fixed in my PR on conda-store but it's not ready yet.
Meanwhile :

  • if collecting all the versions (using pagination) and ordering them from the client side takes less than 2 hours, let's do this.
  • otherwise, just leave them ordered as they appear and we'll fix that later with my PR.

Also, when my PR is finished, this will have to be reworked, as there will be a more convenient endpoint.

List of requested packages - read only mode

Goal : have a react component to display a list of requested packages (read-only)

Figma design :

Capture d’écran 2022-06-15 à 08 23 45

Concepts :

  • a requested package has a name, and a constraint
  • the name of a package has usually around 10 characters, but can go up to 30
  • A constraint states which version of a package the user asked for. it can be either latest, or be made of a rule sign ( >,<,>=,<=,==) followed by a version number. Examples : ==12.3.4, <3.2.1, ...
  • the names and constraints will be given by the API. These informations are shared to give a sense of what to expect and size the components accordingly.

Behavior
The box has a maximum height and overflow content scrolls. Expect this height to be a parameter. Clicking on the arrow collapses/expand the box.

API and data
The API endpoint is like : api/v1/build/<build_id>/ and the data to use are in result['data']['specification']['spec']['dependencies']
( @ostojics Don't focus on the API endpoint for the moment, I just leave this here for later when we connect the UI to the API)

According to the API, you can expect the data to be given under the form:
["python=3.6","pandas","ipykernel",{"pip":["blablabla"]}]
You'll have to filter out the dictionary in it and keep only the strings.

In this case, the result should show something similar to :

• python       == 3.6
• pandas       latest
• ipykernel    latest

Another example :
data :
["python>=3.7","holoviews>=1.14","pandas",{"pip":["random-pip-package"]}]
Expected result similar to :

• python          >= 3.7
• holoviews       >= 1.14
• pandas          latest

Other :
Split this main component into sub-components as necessary.

Unit tests : setup

Goal :

Have the necessary parts to write and run unit tests on components

Technical requirements

  • the chosen framework for tests is Jest
  • Add instructions in the readme about how to run the test suite

Next steps :

  • Write unit tests for existing components ( #33 )
  • Write unit tests for each new component

Add a storybook

Adding examples of the components on the main page isn't a long-term solution.

Let's add a storybook that will help demonstrating every components in a better way.

Unit tests for existing components

Goal :

Have unit tests to check quality of the existing components.

Scope

For this first batch, we'll focus on the components developed so far :

  • List of channels - read-only
  • List of channels - edit mode
  • List of Requested packages - read-only
  • List of Requested packages - edit mode
  • List of dependency packages - read-only
  • List of dependency packages - edit mode

List of namespaces and environments

Goal :

Display the list of namespaces and their environments

Figma design

Capture d’écran 2022-07-05 à 06 38 51

Concepts :

  • a namespace is a set of environments, that some users have access to.
  • Namespaces are created for teams to group their environments.
  • each user has its own namespace, and access to some other groups' namespaces
  • the name of a namespace can go up to 255 characters.
  • the name of an environment can go up to 255 characters.

Behavior

  • The box has a maximum height and overflow content scrolls. Expect this height to be a parameter.
  • Clicking on the arrow left of a namespace's name, collapses/expand the list of environments under a given namespace.
  • Clicking on the "+" button right of namespace's name will lead, later, to opening the environment creation page in a new tab of the UI.
  • Click on the name an environment will lead, later, to opening the environment's details in a new tab of the UI.
  • Entering text in the "search for environment" input text will trigger an API call - more about that later. For the moment, just filter the existing data.

API and data

The API endpoint is like : /api/v1/environment/ which yields a paginated result similar to :

{
   "status":"ok",
   "data":[
      {
         "id":2,
         "namespace":{
            "id":1,
            "name":"default"
         },
         "name":"test_env_1",
         "current_build_id":2,
         "current_build":null
      },
      {
         "id":1,
         "namespace":{
            "id":2,
            "name":"filesystem"
         },
         "name":"python-flask-env",
         "current_build_id":1,
         "current_build":null
      }
   ],
   "message":null,
   "page":1,
   "size":100,
   "count":2
}
  • the environments are ordered by namespace and then by environment name.

( @ostojics Don't focus on the API endpoint for the moment, I just leave this here for later when we connect the UI to the API)

Other :
Split this main component into sub-components as necessary.

Yaml editor : the orders of channels doesn't reflect the yaml composer

In the yaml composer, I've added a channel to an env, and changed their orders, to get this :

Capture d’écran 2022-09-21 à 14 25 27

When I click on the yaml editor, the channels appear in the wrong order.
It's important the channels are sent to the API in the order the user defined (for both editing and creating an env)
Capture d’écran 2022-09-21 à 14 25 35

Page of environment details - read only

Goal :

Have the main page displaying the details of an env - in read only mode.

Figma design

Capture d’écran 2022-07-14 à 15 26 36

Related components :

  • The "environment metadata" block is yet to be done ( issue #28 )
  • The "Specification" block has already its components done ( see issues #3 #8 #10 )
  • the "Logs and Artifacts" block is yet to be done

API and data

The various API endpoints for each component are listed and detailed in each issue. Contact me if it's unclear.

Other :
Split this main component into sub-components as necessary.

List of requested packages - edit mode

Goal :

have a react component that helps defining a list of requested packages with their constraints.
This component can be used with an existing list of requested packages, or an empty list.

Figma design :

Capture d’écran 2022-06-20 à 09 57 41

Concepts :

  • a requested package has a name, and a constraint
  • the name of a package has usually around 10 characters, but can go up to 30
  • A constraint states which version of a package the user asked for. it can be either latest, or be made of a rule sign ( >,<,>=,<=,==) followed by a version number. Examples : ==12.3.4, <3.2.1, ...

Behavior :

  • The box has a maximum height and overflow content scrolls. Expect this height to be a parameter. Clicking on the arrow collapses/expand the box.

  • When given an empty list, the component displays the 3 columns titles (Name, Installed Version, and Version constraint) and the + Add Package button below, similar to :

Name        Installed Version        Version Constraint
————————————————————————————————————————————————————————
+ Add Package
  • When given an existing list of packages, the component displays the data as described in the figma design
  • Clicking on the + Add Package button adds an empty row ready at the bottom of the list, similar to :
Name        Installed Version        Version Constraint
┌────┐        
                                                            🗑     
└────┘        
————————————————————————————————————————————————————————
+ Add Package
  • Once the user has entered text in the name field, the component updates to display the version constraint fields :
Name        Installed Version        Version Constraint
┌──────┐                                  ┌──┐┌─────┐┌──┐
 pandas                                                ▼       🗑
└──────┘                                  └──┘└─────┘└──┘
————————————————————————————————————————————————————————
+ Add Package

Update 2022/06/21 :

  • When adding a new package, the version constraint fields are empty by default
  • Clicking on the left-most column in the version constraint shows a dropdown list of the rule signs ( >,<,>=,<=,==)
  • Clicking on the shows the list of available versions for the selected package (pandas in the above example - mockup this list of versions for the moment)

@ostojics populate the list/select input of constraints with a dummy list for the moment.

  • Clicking on the thrash bin icon removes the row

@ostojics : leave the following points aside for the moment, we'll do them when we connect the components to the API :

  • Entering text in the name input box will trigger autocomplete to select a package
  • Once a package is selected, the list of available constraints will be automatically updated with the available versions for the given package

API and data

According to the API, for a non-empty environment, you can expect the data to be given under the form:
["python=3.6","pandas","ipykernel",{"pip":["blablabla"]}]
You'll have to filter out the dictionary in it and keep only the strings.

For an empty environment, you can expect the data to be given under the form :
[] or with an extraneous dict like : [ {"pip":["blablabla"]}]

We expect the component to be able to return/yield its data when submitting the screen.
These data will have to include any extraneous dictionary given as input (like the one with the pip key), and the list of request packages in the same format.

Other

Split this main component into sub-components as necessary.

Environment metadata block - edit mode

Goal :

Have the block to display metadata of an env and edit its description.

Figma design

The component is similar to #28 but with an editable text field for description :
Capture d’écran 2022-07-14 à 15 23 11

Behavior

  • The validation of the new description will be triggered by the "Create"/"Update" button at the bottom of the page (which validates the whole page and all the other changes)

API and data

There are two major ways of updating the description - it's the developper's responsability to chose the one that makes the most sense, according to the use case (creating a new env or updating an existing one)

1st way : direct API endpoint

The API offers an endpoint to update an environment.

  • You'll need the env's namespace and name to build the endpoint itself.
    For example, for an env named "project_1" in a namespace named "data-science-team", the endpoint is :
    http://localhost:5000/conda-store/api/v1/environment/data-science-team/project_1/
  • You'll need to use method PUT to post data to this endpoint.
  • the payload to send to the endpoint is a json dict with a description key :
{
  "description": "this is a new description of our very cool environment"
}

This endpoint is the most convenient when updating an env

2nd way : POST specification

The POST /conda-store/api/v1/specification/ endpoint allows posting the full YAML description of an env.

_This endpoint is the most convenient when creating an env, see issue #64 _

Other :
Split this main component into sub-components as necessary.

List of channels - read only mode

Goal :

have a react component to display the list of channels specified in an environment (read-only)

Figma design

Capture_decran_2022-06-15_a_14 10 44

Concepts :

  • a 'channel' is a source of packages
  • a channel has a name, max length 255 character

Behavior

  • The box has a maximum height and overflow content scrolls. Expect this height to be a parameter.
  • Clicking on the arrow collapses/expand the box.

API and data

The API endpoint is like : api/v1/build/<build_id>/ and the data to use are in result['data']['specification']['spec']['channel']
( @ostojics Don't focus on the API endpoint for the moment, I just leave this here for later when we connect the UI to the API)

According to the API, you can expect the data to be given under the form:
["conda-store","default", "blablabla"]

Other :
Split this main component into sub-components as necessary.

Add linting and setup github actions

The goal is to have linting, and automated tests run by github actions to validate/invalidate PRs according to the linting results, as we usually have on python projects.

@telamonian : add what's necessary to run linting
@ostojics : add what's necessary to run linting as a github workflow / automated test.

List of channels - edit mode

Goal :

have a react component to define the list of channels to use in an environment

Figma design

Capture d’écran 2022-06-24 à 15 32 44

Concepts :

  • a 'channel' is a source of packages
  • a channel has a name, max length 255 character
  • For the moment, we consider any non-empty string is a valid channel name

Behavior

  • The box has a maximum height and overflow content scrolls. Expect this height to be a parameter.
  • Clicking on the arrow collapses/expand the box.
  • Row containing channel names can be reordered - order matters here.
  • Clicking on the "+ Add channel" button adds a row at the bottom of the component, with an empty textfield.
  • When creating an env from scratch, the list of channels must be empty and only the "+ Add channel" button is shown

API and data

The API endpoint is like : api/v1/build/<build_id>/ and the data to use are in result['data']['specification']['spec']['channel']
( @ostojics Don't focus on the API endpoint for the moment, I just leave this here for later when we connect the UI to the API)

According to the API, you can expect the data to be given under the form:
["conda-store","default", "blablabla"]

It is required that the component returns the data of its content under the same format (an ordered list of strings). We'll need to give this content to the API to build the environment.

Other :
Split this main component into sub-components as necessary.

Login - new approach

The login process is now very simple and straightforward.

Considering the following context :

  • conda store running on http://localhost:5000/conda-store
  • the UI running on http://localhost
    (in production, we need both to run under the same domain name)

Then, the login process is the following:

  • access the login url : http://localhost:5000/conda-store/login?next=http://localhost (notice the next parameter)
  • once logged in, the API calls now work using a cookie - I've tested this manually, removing the env, and it worked perfectly.

What needs to be done :

  • define an env var to store the login page http://localhost:5000/conda-store/login?next=
  • in the UI, the login button must redirect to LOGIN_PAGE_URL and set the next parameter accordingly (take into account that the UI could be running on websites like https://mywebsite.com or http://localhost:8080)
  • get rid of the token

Then, it's expected the login process works and the API calls work.

Extra bit of information :
by running the following Javascript code :

fetch("https://conda-store.localhost/conda-store/api/v1/permission/", {credentials: "include"}).then((r) => r.json()).then((d) => console.log(d.data.authenticated)) 

We can check if the user is authenticated.
That will be necessary for a logout button - will be done in another issue.

Add a package : autocomplete the name

The component to add a package to an env requires autocomplete.

The API endpoint to find a package is :
http://localhost:5000/conda-store/api/v1/package/?search=[SEARCH_STRING]&page=[PAGE NUMBER]

For example, searching num to add numpy :
http://localhost:5000/conda-store/api/v1/package/?search=num&page=1

It yields a result similar to :

{
  "status": "ok",
  "data": [
    {
      "id": 48,
      "channel": {
        "id": 1,
        "name": "https://conda.anaconda.org/main",
        "last_update": null
      },
      "build": "py_0",
      "license": "MIT",
      "sha256": "02653c4b2407edd0f7d0f3410d3aa5d8dcdaf295d72450770c8544ea394a2dc1",
      "name": "marshmallow-enum",
      "version": "1.5.1",
      "summary": "Enum handling for Marshmallow"
    },
    {
      "id": 1704,
      "channel": {
        "id": 1,
        "name": "https://conda.anaconda.org/main",
        "last_update": null
      },
      "build": "pyhd3eb1b0_0",
      "license": "MIT",
      "sha256": "5b8b1be99ec2ac02b61c6167c7f0577ac191cec1acc581cd7884e672d75eb33d",
      "name": "marshmallow-enum",
      "version": "1.5.1",
      "summary": "Enum handling for Marshmallow"
    },
    {
      "id": 2787,
      "channel": {
        "id": 1,
        "name": "https://conda.anaconda.org/main",
        "last_update": null
      },
      "build": "py_0",
      "license": "BSD 3-Clause",
      "sha256": "96883bcb026d68cd4757ecb7bada6057d961513c461a8a9f137e8d79edcc784d",
      "name": "msgpack-numpy",
      "version": "0.4.4.3",
      "summary": "Numpy data serialization using msgpack"
    },
    {
      "id": 2982,
      "channel": {
        "id": 1,
        "name": "https://conda.anaconda.org/main",
        "last_update": null
      },
      "build": "py_0",
      "license": "BSD 3-Clause",
      "sha256": "a124069df2d8a55ef5b84b2f51e683d8d4dd295595b145060a2256d455a20447",
      "name": "msgpack-numpy",
      "version": "0.4.7",
      "summary": "Numpy data serialization using msgpack"
    },
    ...
    {
      "id": 2530,
      "channel": {
        "id": 1,
        "name": "https://conda.anaconda.org/main",
        "last_update": null
      },
      "build": "pyhd3eb1b0_0",
      "license": "Apache-2.0",
      "sha256": "89c954d18fb687d5075fa5044082beafed67029e76a2ae4f4d5ead18d589c317",
      "name": "phonenumbers",
      "version": "8.12.25",
      "summary": "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers."
    },
    {
      "id": 1648,
      "channel": {
        "id": 1,
        "name": "https://conda.anaconda.org/main",
        "last_update": null
      },
      "build": "pyhd3eb1b0_0",
      "license": "Apache-2.0",
      "sha256": "59100abc0aaf956a09db8867ddce6230bf02648a6c1ab2baa9012d6795fa2f0b",
      "name": "phonenumbers",
      "version": "8.12.27",
      "summary": "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers."
    },
    {
      "id": 1736,
      "channel": {
        "id": 1,
        "name": "https://conda.anaconda.org/main",
        "last_update": null
      },
      "build": "py_0",
      "license": "Apache 2.0",
      "sha256": "5e10e983bd9b38a830f44cc7cf76d8a0ce1736f42aebcd6acf84d0da11fa70c8",
      "name": "phonenumbers",
      "version": "8.12.9",
      "summary": "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers."
    }
  ],
  "message": null,
  "page": 1,
  "size": 100,
  "count": 26
}

The result contains the corresponding packages containing the search string, and all their versions and builds.
For this first step, you'll have to deduplicate the result to keep only the name, and display them in the suggestions list of the field.

Later, when my PR on conda-store is finished, this will have to be reworked. The endpoint will return only the packages and their names, not duplicated by version.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.