From 535526d8b20ebf41f38cdce2abee614fe59d2cb3 Mon Sep 17 00:00:00 2001 From: Ignacio Talavera <ignaciotalaveracepeda@gmail.com> Date: Mon, 13 May 2024 09:13:37 +0200 Subject: [PATCH 1/7] Adding LlamaIndex docs to integrations (#4803) Closes #4798 --------- Co-authored-by: sdiazlor <sdiazlor@gmail.com> --- .../llama_index/argilla-ui-dataset.png | Bin 0 -> 102735 bytes docs/_source/index.rst | 3 +- .../integrations/integrations.md | 6 + .../integrations/llama_index.ipynb | 212 ++++++++++++++++++ 4 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 docs/_source/_static/tutorials/llama_index/argilla-ui-dataset.png create mode 100644 docs/_source/tutorials_and_integrations/integrations/llama_index.ipynb diff --git a/docs/_source/_static/tutorials/llama_index/argilla-ui-dataset.png b/docs/_source/_static/tutorials/llama_index/argilla-ui-dataset.png new file mode 100644 index 0000000000000000000000000000000000000000..2d4b25b33e47675d3f6ae84f9914e75aae20d253 GIT binary patch literal 102735 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Πx%7=9meH-4JjXh3rDDtjf><+fO)uu`jj2 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�^|3!I}|&6+<o5QV&|li-D$na`r6c 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�W1PPWR>+h6h2?qn#G)k%uTGSbmbcvZod{r(uW z$f2+H%?$U-G%1)cs9JGvV~H}RINa5oh55Rc+k%j_p<byj$LNNRyH)Z($K`fDzjvV? zd((2~d&}IdX^m2-$F&if-z9)mE(t>Xey9)8^dyl(sQW>^QN~tEQUbzWmTgx^eiAs% z)wWc(xFy;gK(;GDJQT&e!Iwh*N$Nj7EIfGvf3Jg_`rJSM{)-#}UC6lr<8zT>+iU#y zfB)<wB+z$JJWlWR(SMF&S4e;Kkxg;b2Zo{F6Ws%Q_Ol^*g6b`PuW(>bd!J|-%WZ%M zT5jx4@xeWtv$0~E(`h)b{Z7a~n)aIpcs&i-pY&Z${`MX#Bftu=T%nWy-sMfY6L`H6 zk+6SffA7(wK1C0nzBsU_Jz|r}d>2c~;zR#j$-n;PlOnKPsPn2l`S&inNI6;XNW<Le zBJn?oOZq~L4q_NE`FL_y@B?niZAjhKD*vaz9X)X--gnW}IciN|m(DgXzZd?fxwQ`& zZCC-=AA+Z)d&pWz)b`B->fN^06mEa}Z0)h0?&_eCx=y9C+tBXpeln~s(?-u-l-Omp zA0=twQ6H&zjc1qA_qyGEn^j2JulU|*x}P$nx?oRGr#XebFN*u6)vq7*oq<fh7W}7# z-1Z`Vko$=(v3|n3b&s9Rr$3#?suxc^G9l`33ReT|{p06@AKl4(jg|9;(C9s813;K8 zE<vsx9^;-2rOlOXTn`2lhkerY&q1-u4X2T%y1Xrx84VhWR-BjHYx@}WCmyUia_XCm z@npuLtI!!HEbmdf9)k=f!uT(kR8Jsje8`D@a1U`hU*=*0GR?YnWz|jn6XKiOo4Lqc zVv;ERX5SBefNmtC0>m=^oaWzXswFdDjzQH%-nsNo*8KJwNdxT(eAIwX*WUCUB(!ZO zfYl+-kVUyWWe2wT|Gz1}x3xnxx7$vTTl`7&CH3k)P={nT%P!4+mSmJPcqC?Sa(%nC z50$vL81}z?{aVhjT*dm9*zPxnh&hf@x{P7wAZDJP<s@99d#YpaqfRZ>T;nuRKE^$s z_?;qoM($&2X=!F{4g0_NhRUa-oJ(9>Ts2>ZZLhK22f09!_E?Z%`6)a)^FjLFq7sUz z*7|BMxzygSlarhKaejVYi~8d0U5VMB>gr6Ac0-V1k&3ncFM~@1DsSL5G&PknI$ro6 zKTGbbDq-FE#}5AK7Aq<0K`u|OK^lVhmtpFVJfrfV?)>)c?(E#$N8I+hG;vvkh*JEX z=<hBoO49a}gboIfAxy<u@0ad5$kYO}dsdFdo51N{FjzrB!NWxZp5O&?yAq|ai@{de zYk*qy>pPnIk^Jv&Be;eaeB7n=zjqMhpgU9cdK((Bu52NzVtL2cwO?O4#<hMem0oa( zpTJl2J==7j5_nw0+CCJp(hF1(2Nx6-QBzP*Tm<~Rl(2$*8m+j63Kzvei2~WW!*K%0 zj_$3kt(uf1rPahWL-M#kS5I{hNqb6sMtXWOW{xFCHLcuR_4tSSXSVfwP4-d*T*9h% zrN5dvP3-Avu~sR5bzh$L-r9d)U>|mGI%buw^P5K6pSvHkc|jl0iFOO1T?=Y=yWJB+ n!h_snK)?QPQ~y(5;SU|*v}7%{yVgep{3u`7P{_M>`_caa@<ewj literal 0 HcmV?d00001 diff --git a/docs/_source/index.rst b/docs/_source/index.rst index d15b6fe689..0fb7317be6 100644 --- a/docs/_source/index.rst +++ b/docs/_source/index.rst @@ -66,5 +66,4 @@ Github <https://github.com/argilla-io/argilla> community/developer_docs community/contributing - community/migration-rubrix.md - + community/migration-rubrix.md \ No newline at end of file diff --git a/docs/_source/tutorials_and_integrations/integrations/integrations.md b/docs/_source/tutorials_and_integrations/integrations/integrations.md index 83e4ed1114..98cd7c7a8f 100644 --- a/docs/_source/tutorials_and_integrations/integrations/integrations.md +++ b/docs/_source/tutorials_and_integrations/integrations/integrations.md @@ -30,6 +30,11 @@ Add text descriptives to your metadata to simplify the data annotation and filte Add semantic representations to your records using vector embeddings to simplify the data annotation and search process. ``` +```{grid-item-card} llama-index: Build LLM applications with LlamaIndex. +:link: llama_index.html + +Build LLM applications with LlamaIndex and automatically log and monitor the predictions with Argilla. +``` ```` ```{toctree} @@ -40,4 +45,5 @@ process_documents_with_unstructured monitor_endpoints with_fastapi add_text_descriptives_as_metadata add_sentence_transformers_embeddings_as_vectors +llama_index ``` \ No newline at end of file diff --git a/docs/_source/tutorials_and_integrations/integrations/llama_index.ipynb b/docs/_source/tutorials_and_integrations/integrations/llama_index.ipynb new file mode 100644 index 0000000000..52a240d922 --- /dev/null +++ b/docs/_source/tutorials_and_integrations/integrations/llama_index.ipynb @@ -0,0 +1,212 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# `llamaindex`: Build LLM applications with LlamaIndex and monitor the data with Argilla.\n", + "\n", + "This integration allows the user to include the feedback loop that Argilla offers into the LlamaIndex ecosystem. It's based on a callback handler to be run within the LlamaIndex workflow.\n", + "\n", + "LlamaIndex is a specialized data framework tailored for supporting LLM-driven application development. It provides a sophisticated structure enabling developers to seamlessly integrate various data sources with large language models. These sources encompass diverse file formats like PDFs and PowerPoints, popular applications such as Notion and Slack, and databases like Postgres and MongoDB. Through a range of connectors, the framework streamlines data ingestion, facilitating smooth interactions with LLMs. Additionally, LlamaIndex offers an efficient interface for data retrieval and queries. This functionality allows developers to input LLM prompts and receive context-rich, knowledge-enhanced outputs.\n", + "\n", + "In essence, LlamaIndex acts as an intermediary for managing interactions with an LLM by constructing an index from input data. This index is then leveraged to answer queries related to the provided data. LlamaIndex is flexible, capable of generating different types of indexes—vector, tree, list, or keyword indexes—tailored to specific requirements.\n", + "\n", + "LlamaIndex offers a wide array of tools that facilitate the processes of data ingestion, retrievals, structuring, and integration with diverse application frameworks.\n", + "Don't hesitate to check out both [LlamaIndex](https://github.com/run-llama/llama_index) and [Argilla](https://github.com/argilla-io/argilla)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Running Argilla\n", + "\n", + "For this tutorial, you will need to have an Argilla server running. There are two main options for deploying and running Argilla:\n", + "\n", + "\n", + "**Deploy Argilla on Hugging Face Spaces**: If you want to run tutorials with external notebooks (e.g., Google Colab) and you have an account on Hugging Face, you can deploy Argilla on Spaces with a few clicks:\n", + "\n", + "[![deploy on spaces](https://huggingface.co/datasets/huggingface/badges/raw/main/deploy-to-spaces-lg.svg)](https://huggingface.co/new-space?template=argilla/argilla-template-space)\n", + "\n", + "For details about configuring your deployment, check the [official Hugging Face Hub guide](https://huggingface.co/docs/hub/spaces-sdks-docker-argilla).\n", + "\n", + "\n", + "**Launch Argilla using Argilla's quickstart Docker image**: This is the recommended option if you want [Argilla running on your local machine](../../getting_started/quickstart.ipynb). Note that this option will only let you run the tutorial locally and not with an external notebook service.\n", + "\n", + "For more information on deployment options, please check the Deployment section of the documentation.\n", + "\n", + "<div class=\"alert alert-info\">\n", + "\n", + "Tip\n", + " \n", + "This tutorial is a Jupyter Notebook. There are two options to run it:\n", + "\n", + "- Use the Open in Colab button at the top of this page. This option allows you to run the notebook directly on Google Colab. Don't forget to change the runtime type to GPU for faster model training and inference.\n", + "- Download the .ipynb file by clicking on the View source link at the top of the page. This option allows you to download the notebook and run it on your local machine or on a Jupyter notebook tool of your choice.\n", + "</div>" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Getting started\n", + "\n", + "You first need to install argilla and argilla-llama-index as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%pip install argilla-llama-index" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Usage\n", + "\n", + "It requires just a simple step to log your data into Argilla within your LlamaIndex workflow. We just need to call the handler before starting production with your LLM. We will use GPT3.5 from OpenAI as our LLM. For this, you will need a valid API key from OpenAI. You can have more info and get one via [this link](https://openai.com/blog/openai-api). After you get your API key, the easiest way to import it is through an environment variable, or via *getpass()*." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "openai_api_key = os.getenv(\"OPENAI_API_KEY\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's now write all the necessary imports and initialize the Argilla client." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "from llama_index.core import VectorStoreIndex, ServiceContext, SimpleDirectoryReader, set_global_handler\n", + "from llama_index.llms.openai import OpenAI\n", + "\n", + "import argilla as rg\n", + "\n", + "rg.init(\n", + " api_url=\"http://localhost:6900\",\n", + " api_key=\"owner.apikey\",\n", + " workspace=\"admin\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we will set up an Argilla global handler for Llama Index. By doing so, we ensure that the predictions that we obtain using Llama Index is automatically uploaded to the Argilla client we initialized before Within the handler, we need to provide the dataset name that we will use. If the dataset does not exist, it will be created with the given name. You can also set the `API KEY`, `API URL`, and the `workspace` name. You can learn more about the variables that controls Argilla initialization [here](https://docs.argilla.io/en/latest/getting_started/installation/configurations/workspace_management.html)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "set_global_handler(\"argilla\", dataset_name=\"query_model\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's now create the `llm` instance, using GPT-3.5 from OpenAI." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "llm = OpenAI(model=\"gpt-3.5-turbo\", temperature=0.8, openai_api_key=openai_api_key)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With the code snippet below, you can create a basic workflow with LlamaIndex. You will also need a `txt` file as the data source within a folder `data`. We have an example `.txt` file ready for you inside that folder, obtained from the [Llama Index documentation](https://docs.llamaindex.ai/en/stable/getting_started/starter_example.html)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "service_context = ServiceContext.from_defaults(llm=llm)\n", + "docs = SimpleDirectoryReader(\"../../data\").load_data()\n", + "index = VectorStoreIndex.from_documents(docs, service_context=service_context)\n", + "query_engine = index.as_query_engine()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let's run the `query_engine` to have a response from the model." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "response = query_engine.query(\"What did the author do growing up?\")\n", + "response" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As the global handler was set, an Argilla dataset is created, with the dataset name that we introduced as parameter. Everything predicted using the `query` function will be automatically logged in this dataset, with information about the steps to produce the prediction. The prompt given and the response are logged, as you can see on this example of Argilla's UI:\n", + "\n", + "![Argilla Dataset](../../_static/tutorials/llama_index/argilla-ui-dataset.png)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From a422e2791fa045073b988f0506a5ae8dfca66b42 Mon Sep 17 00:00:00 2001 From: Sara Han <127759186+sdiazlor@users.noreply.github.com> Date: Mon, 13 May 2024 09:14:03 +0200 Subject: [PATCH 2/7] docs: use FeedbackDataset in HF example (#4805) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit <!-- Thanks for your contribution! As part of our Community Growers initiative 🌱, we're donating Justdiggit bunds in your name to reforest sub-Saharan Africa. To claim your Community Growers certificate, please contact David Berenstein in our Slack community or fill in this form https://tally.so/r/n9XrxK once your PR has been merged. --> # Description ![screencapture-127-0-0-1-8000-getting-started-installation-deployments-huggingface-spaces-html-2024-05-08-14_03_04](https://github.com/argilla-io/argilla/assets/127759186/e118e0b2-5689-45e6-bc08-a744fd32dde3) Closes #4740 **Type of change** (Remember to title the PR according to the type of change) - [ ] Documentation update **How Has This Been Tested** (Please describe the tests that you ran to verify your changes.) - [ ] `sphinx-autobuild` (read [Developer Documentation](https://docs.argilla.io/en/latest/community/developer_docs.html#building-the-documentation) for more details) **Checklist** - [ ] I added relevant documentation - [ ] I followed the style guidelines of this project - [ ] I did a self-review of my code - [ ] I made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I filled out [the contributor form](https://tally.so/r/n9XrxK) (see text above) - [ ] I have added relevant notes to the `CHANGELOG.md` file (See https://keepachangelog.com/) --- .../deployments/huggingface-spaces.md | 102 ++++++++---------- 1 file changed, 43 insertions(+), 59 deletions(-) diff --git a/docs/_source/getting_started/installation/deployments/huggingface-spaces.md b/docs/_source/getting_started/installation/deployments/huggingface-spaces.md index 229d8005ab..f5169c3a2e 100644 --- a/docs/_source/getting_started/installation/deployments/huggingface-spaces.md +++ b/docs/_source/getting_started/installation/deployments/huggingface-spaces.md @@ -55,83 +55,67 @@ Once Argilla is running, you can use the UI with the Direct URL. This URL gives ### Create your first dataset -If everything goes well, you are ready to use the Argilla Python client from an IDE such as Colab, Jupyter, or VS Code. - -If you want a quick step-by-step example, keep reading. If you want an end-to-end tutorial, go to this [tutorial and use Colab or Jupyter](https://docs.argilla.io/en/latest/tutorials/notebooks/training-textclassification-setfit-fewshot.html). - -First, we need to pip install `datasets` and `argilla` on Colab or your local machine: +To create your first dataset, you need to pip install `argilla` on Colab or your local machine: ```bash -pip install datasets argilla -``` - -Then, you can read the example dataset using the `datasets` library. This dataset is a CSV file uploaded to the Hub using the drag-and-drop feature. - -```python -from datasets import load_dataset - -dataset = load_dataset("dvilasuero/banking_app", split="train").shuffle() +pip install argilla ``` -You can create your first dataset by logging it into Argilla using your endpoint URL: +Then, you have to connect to your Argilla HF Space. Get the `api_url` as mentioned before and copy the `api_key` from "My settings" (UI): ```python import argilla as rg -# if you connect to your public app endpoint (uses default API key) -rg.init(api_url="[your_space_url]", api_key="admin.apikey") - -# if you connect to your private app endpoint (uses default API key) -rg.init(api_url="[your_space_url]", api_key="admin.apikey", extra_headers={"Authorization": f"Bearer {os.environ['HF_TOKEN']}"}) - -# transform dataset into Argilla's format and log it -rg.log(rg.read_datasets(dataset, task="TextClassification"), name="bankingapp_sentiment") +# If you connect to your public HF Space +rg.init( + api_url="[your_space_url]", + api_key="admin.apikey" # this is the default API key, don't change it if you didn't set up one during the Space creation + ) + +# If you connect to your private HF Space +rg.init( + api_url="[your_space_url]", + api_key="admin.apikey", # this is the default API key, don't change it if you didn't set up one during the Space creation + extra_headers={"Authorization": f"Bearer {os.environ['HF_TOKEN']}"} + ) ``` - -Congrats! You now have a dataset available from the Argilla UI to start browsing and labeling. In the code above, we've used one of the many integrations with Hugging Face libraries, which let you read hundreds of datasets available on the Hub. - -### Data labeling and model training - -At this point, you can label your data directly using your Argilla Space and read the training data to train your model of choice. +Now, create a dataset for text classification. We'll use a task template, check the [docs](../../../practical_guides/create_update_dataset/create_dataset.md) to create a custom dataset. Indicate the workspace where the dataset will be created. You can check them in "My settings" (UI). ```python -# this will read our current dataset and turn it into a clean dataset for training -dataset = rg.load("bankingapp_sentiment").prepare_for_training() +dataset = rg.FeedbackDataset.for_text_classification( + labels=["sadness", "joy"], + multi_label=False, + use_markdown=True, + guidelines=None, + metadata_properties=None, + vectors_settings=None, +) +# Create the dataset to be visualized in the UI (uses default workspace) +dataset.push_to_argilla(name="my-first-dataset", workspace="admin") ``` - -You can also get the full dataset and push it to the Hub for reproducibility and versioning: +To add the records, create a list with the records you want to add. Match the fields with the ones specified before. You can also use pandas or `load_dataset` to read an existing dataset and create records from it. ```python -# save full argilla dataset for reproducibility -rg.load("bankingapp_sentiment").to_datasets().push_to_hub("bankingapp_sentiment") +records = [ + rg.FeedbackRecord( + fields={ + "text": "I am so happy today", + }, + ), + rg.FeedbackRecord( + fields={ + "text": "I feel sad today", + }, + ) +] +dataset.add_records(records) ``` -Finally, this is how you can train a SetFit model using data from your Argilla Space: +Congrats! You now have a dataset available from the Argilla UI to start browsing and labeling. Once annotated, you can also easily push it back to the Hub. ```python -from sentence_transformers.losses import CosineSimilarityLoss - -from setfit import SetFitModel, SetFitTrainer - -# Create train test split -dataset = dataset.train_test_split() - -# Load SetFit model from Hub -model = SetFitModel.from_pretrained("sentence-transformers/paraphrase-mpnet-base-v2") - -# Create trainer -trainer = SetFitTrainer( - model=model, - train_dataset=dataset["train"], - eval_dataset=dataset["test"], - loss_class=CosineSimilarityLoss, - batch_size=8, - num_iterations=20, -) - -# Train and evaluate -trainer.train() -metrics = trainer.evaluate() +dataset = rg.FeedbackDataset.from_argilla("my-first-dataset", workspace="admin") +dataset.push_to_huggingface("my-repo/my-first-dataset") ``` As a next step, you can check the [Argilla Tutorials](https://docs.argilla.io/en/latest/tutorials/tutorials.html) section. All the tutorials can be run using Colab or local Jupyter Notebooks, so you can start building datasets with Argilla and Spaces! From e466946dd84e349e89084fca71668d13268bfe4f Mon Sep 17 00:00:00 2001 From: Sara Han <127759186+sdiazlor@users.noreply.github.com> Date: Mon, 13 May 2024 09:14:57 +0200 Subject: [PATCH 3/7] docs: clarification/typo in tutorial (#4810) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit <!-- Thanks for your contribution! As part of our Community Growers initiative 🌱, we're donating Justdiggit bunds in your name to reforest sub-Saharan Africa. To claim your Community Growers certificate, please contact David Berenstein in our Slack community or fill in this form https://tally.so/r/n9XrxK once your PR has been merged. --> # Description Please include a summary of the changes and the related issue. Please also include relevant motivation and context. List any dependencies that are required for this change. Closes #4809 **Type of change** (Remember to title the PR according to the type of change) - [ ] Documentation update **How Has This Been Tested** (Please describe the tests that you ran to verify your changes.) - [ ] `sphinx-autobuild` (read [Developer Documentation](https://docs.argilla.io/en/latest/community/developer_docs.html#building-the-documentation) for more details) **Checklist** - [ ] I added relevant documentation - [ ] I followed the style guidelines of this project - [ ] I did a self-review of my code - [ ] I made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I filled out [the contributor form](https://tally.so/r/n9XrxK) (see text above) - [ ] I have added relevant notes to the `CHANGELOG.md` file (See https://keepachangelog.com/) --- .../installation/configurations/user_management.md | 2 +- .../configurations/workspace_management.md | 4 ++-- .../feedback/end2end_examples/add-vectors-004.ipynb | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/_source/getting_started/installation/configurations/user_management.md b/docs/_source/getting_started/installation/configurations/user_management.md index 9638ec2863..fd791b046a 100644 --- a/docs/_source/getting_started/installation/configurations/user_management.md +++ b/docs/_source/getting_started/installation/configurations/user_management.md @@ -182,7 +182,7 @@ import argilla as rg rg.init(api_url="<ARGILLA_API_URL>", api_key="<ARGILLA_API_KEY>") -user = rg.User.from_id("new-user") +user = rg.User.from_id("00000000-0000-0000-0000-000000000000") ``` ### Assign a `User` to a `Workspace` diff --git a/docs/_source/getting_started/installation/configurations/workspace_management.md b/docs/_source/getting_started/installation/configurations/workspace_management.md index bc681138c9..3e2ecc2cf3 100644 --- a/docs/_source/getting_started/installation/configurations/workspace_management.md +++ b/docs/_source/getting_started/installation/configurations/workspace_management.md @@ -163,8 +163,8 @@ workspace = rg.Workspace.from_name("new-workspace") users = workspace.users for user in users: ... -workspace.add_user("<USER_ID>") -workspace.delete_user("<USER_ID>") +workspace.add_user(user.id) +workspace.delete_user(user.id) ``` ::: diff --git a/docs/_source/tutorials_and_integrations/tutorials/feedback/end2end_examples/add-vectors-004.ipynb b/docs/_source/tutorials_and_integrations/tutorials/feedback/end2end_examples/add-vectors-004.ipynb index 518df3d7a5..f882042088 100644 --- a/docs/_source/tutorials_and_integrations/tutorials/feedback/end2end_examples/add-vectors-004.ipynb +++ b/docs/_source/tutorials_and_integrations/tutorials/feedback/end2end_examples/add-vectors-004.ipynb @@ -394,7 +394,7 @@ "metadata": {}, "outputs": [], "source": [ - "dataset.update_records(modified_records)" + "dataset_remote.update_records(modified_records)" ] }, { @@ -403,9 +403,9 @@ "source": [ "## Find Similar Records\n", "\n", - "Now that we have the vectors for each record, let us see the semantic search in action. We can accomplish this via both the UI and PythonSDK. To find similar records in the UI, please refer to the [push the dataset](#Push-the-Dataset) section, where we upload the improved dataset to Argilla server and easily do semantic search. In this section, we will see how to do it within the PythonSDK.\n", + "Now that we have the vectors for each record, let's see the semantic search in action. We can accomplish this via both the UI and PythonSDK. To find similar records in the UI, please refer to the [push the dataset](#Push-the-Dataset) section, where we upload the improved dataset to Argilla server and easily do semantic search. In this section, we will see how to do it within the PythonSDK.\n", "\n", - "To find similar records, we will use the `find_similar_records` method. We need to feed this method with the vector name we want to use for the search. For the particular vector, we have two options: we can either use a record by the `record` parameter or we can define a new vector by the `vector` parameter. You can limit the number of records you want to get by the `max_results` parameter. " + "To find similar records, we will use the `find_similar_records` method, which only works with a remote dataset. We need to feed this method with the vector name we want to use for the search. For the particular vector, we have two options: we can either use a record by the `record` parameter or we can define a new vector by the `vector` parameter. You can limit the number of records you want to get by the `max_results` parameter. " ] }, { @@ -414,9 +414,9 @@ "metadata": {}, "outputs": [], "source": [ - "similar_records = dataset.find_similar_records(\n", + "similar_records = dataset_remote.find_similar_records(\n", " vector_name=\"sentence_embedding\",\n", - " record=dataset[0],\n", + " record=dataset_remote[0],\n", " max_results=5\n", ")" ] From 4316263fc8c1cc99fef8ef77f0ae95ba9ac38d55 Mon Sep 17 00:00:00 2001 From: sdiazlor <sdiazlor@gmail.com> Date: Wed, 15 May 2024 11:07:56 +0200 Subject: [PATCH 4/7] docs: labels_order --- docs/_source/_common/tabs/question_settings.md | 3 ++- .../practical_guides/create_update_dataset/create_dataset.md | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/_source/_common/tabs/question_settings.md b/docs/_source/_common/tabs/question_settings.md index bba3763418..a75c46f787 100644 --- a/docs/_source/_common/tabs/question_settings.md +++ b/docs/_source/_common/tabs/question_settings.md @@ -24,7 +24,8 @@ rg.MultiLabelQuestion( description="Select all that apply", labels={"hate": "Hate Speech" , "sexual": "Sexual content", "violent": "Violent content", "pii": "Personal information", "untruthful": "Untruthful info", "not_english": "Not English", "inappropriate": "Inappropriate content"}, # or ["hate", "sexual", "violent", "pii", "untruthful", "not_english", "inappropriate"] required=False, - visible_labels=4 + visible_labels=4, + labels_order="natural" ) ``` diff --git a/docs/_source/practical_guides/create_update_dataset/create_dataset.md b/docs/_source/practical_guides/create_update_dataset/create_dataset.md index 8b60dd6f28..b5db3b7072 100644 --- a/docs/_source/practical_guides/create_update_dataset/create_dataset.md +++ b/docs/_source/practical_guides/create_update_dataset/create_dataset.md @@ -95,6 +95,7 @@ The following arguments apply to specific question types: - `field`: A `SpanQuestion` is always attached to a specific field. Here you should pass a string with the name of the field where the labels of the `SpanQuestion` should be used. - `allow_overlapping`: In a `SpanQuestion`, this value specifies whether overlapped spans are allowed or not. It is set to `False` by default. Set to `True` to allow overlapping spans. - `visible_labels` (optional): In `LabelQuestion`, `MultiLabelQuestion` and `SpanQuestion` this is the number of labels that will be visible at first sight in the UI. By default, the UI will show 20 labels and collapse the rest. Set your preferred number to change this limit or set `visible_labels=None` to show all options. +- `labels_order` (optional): In `MultiLabelQuestion`, this determines the order in which labels are displayed in the UI. Set it to `natural` to show labels in the order they were defined, or `suggestion` to prioritize labels associated with suggestions. If scores are available, labels will be ordered by score. Defaults to `natural`. - `use_markdown` (optional): In `TextQuestion` define whether the field should render markdown text. Defaults to `False`. If you set it to `True`, you will be able to use all the Markdown features for text formatting, as well as embed multimedia content and PDFs. To delve further into the details, please refer to this [tutorial](/tutorials_and_integrations/tutorials/feedback/making-most-of-markdown.ipynb). ```{note} From 055e7c788fe9f8ad008d00ed9f603f9732a83cc8 Mon Sep 17 00:00:00 2001 From: Sara Han <127759186+sdiazlor@users.noreply.github.com> Date: Wed, 15 May 2024 16:18:50 +0200 Subject: [PATCH 5/7] Update docs/_source/practical_guides/create_update_dataset/create_dataset.md Co-authored-by: Natalia Elvira <126158523+nataliaElv@users.noreply.github.com> --- .../practical_guides/create_update_dataset/create_dataset.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_source/practical_guides/create_update_dataset/create_dataset.md b/docs/_source/practical_guides/create_update_dataset/create_dataset.md index b5db3b7072..cc9510583c 100644 --- a/docs/_source/practical_guides/create_update_dataset/create_dataset.md +++ b/docs/_source/practical_guides/create_update_dataset/create_dataset.md @@ -95,7 +95,7 @@ The following arguments apply to specific question types: - `field`: A `SpanQuestion` is always attached to a specific field. Here you should pass a string with the name of the field where the labels of the `SpanQuestion` should be used. - `allow_overlapping`: In a `SpanQuestion`, this value specifies whether overlapped spans are allowed or not. It is set to `False` by default. Set to `True` to allow overlapping spans. - `visible_labels` (optional): In `LabelQuestion`, `MultiLabelQuestion` and `SpanQuestion` this is the number of labels that will be visible at first sight in the UI. By default, the UI will show 20 labels and collapse the rest. Set your preferred number to change this limit or set `visible_labels=None` to show all options. -- `labels_order` (optional): In `MultiLabelQuestion`, this determines the order in which labels are displayed in the UI. Set it to `natural` to show labels in the order they were defined, or `suggestion` to prioritize labels associated with suggestions. If scores are available, labels will be ordered by score. Defaults to `natural`. +- `labels_order` (optional): In `MultiLabelQuestion`, this determines the order in which labels are displayed in the UI. Set it to `natural` to show labels in the order they were defined, or `suggestion` to prioritize labels associated with suggestions. If scores are available, labels will be ordered by descending score. Defaults to `natural`. - `use_markdown` (optional): In `TextQuestion` define whether the field should render markdown text. Defaults to `False`. If you set it to `True`, you will be able to use all the Markdown features for text formatting, as well as embed multimedia content and PDFs. To delve further into the details, please refer to this [tutorial](/tutorials_and_integrations/tutorials/feedback/making-most-of-markdown.ipynb). ```{note} From 24e1dc8af2e10a7b945e80cec99281b3e20f6c1d Mon Sep 17 00:00:00 2001 From: Sara Han <127759186+sdiazlor@users.noreply.github.com> Date: Thu, 16 May 2024 16:59:03 +0200 Subject: [PATCH 6/7] docs/fix: revert changes in main (#4838) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit <!-- Thanks for your contribution! As part of our Community Growers initiative 🌱, we're donating Justdiggit bunds in your name to reforest sub-Saharan Africa. To claim your Community Growers certificate, please contact David Berenstein in our Slack community or fill in this form https://tally.so/r/n9XrxK once your PR has been merged. --> # Description Due to the wrong merge of a branch (https://github.com/argilla-io/argilla/pull/4835/commits) with the source in develop without rebase into `main`, this PR reverts those commits --- CHANGELOG.md | 4 - environment_dev.yml | 2 +- .../base/base-range/BaseRangeSlider.vue | 61 ++-- .../base/base-switch/BaseSwitch.vue | 34 +- .../base/base-table/BaseTableInfo.vue | 1 - ...ntent.vue => LeftUserSettings.content.vue} | 8 +- ...Header.vue => TopUserSettings.content.vue} | 8 +- .../LeftDatasetSettings.content.vue | 1 - .../TopDatasetSettings.content.vue | 3 - .../dataset-progress/DatasetProgress.vue | 2 - .../SpanAnnotationTextField.component.vue | 2 +- .../components/EntityComponent.vue | 3 +- .../components/EntityDropdown.vue | 2 +- .../components/highlighting.ts | 8 +- .../DndSelection.component.vue | 6 +- .../LabelSelection.component.vue | 65 ++-- .../questions/form/span/EntityLabelBadge.vue | 3 + .../header/DatasetFilters.component.vue | 8 +- .../feedback-task/header/SearchBar.base.vue | 174 ++++++++++ .../search-bar-filter/SearchBarFilter.vue | 300 ------------------ .../header/useDatasetsFiltersViewModel.ts | 17 +- .../settings/SettingsDangerZone.vue | 2 +- .../feedback-task/settings/SettingsFields.vue | 22 +- .../feedback-task/settings/SettingsInfo.vue | 4 +- .../settings/SettingsInfoReadOnly.vue | 2 +- .../settings/SettingsMetadata.vue | 28 +- .../settings/SettingsQuestions.vue | 108 ++----- .../settings/SettingsVectors.vue | 6 +- frontend/layouts/HeaderAndOneColumn.vue | 48 +++ .../layouts/HeaderAndTopAndTwoColumns.vue | 67 ++++ frontend/layouts/InternalPage.vue | 35 -- frontend/package.json | 2 +- .../useAnnotationModeViewModel.ts | 2 +- frontend/pages/dataset/_id/settings.vue | 64 ++-- .../datasets/_workspace/_dataset/settings.vue | 16 +- frontend/pages/user-settings.vue | 16 +- frontend/translation/de.js | 2 - frontend/translation/en.js | 5 +- frontend/v1/di/di.ts | 3 - .../v1/domain/entities/question/Question.ts | 17 +- .../entities/question/QuestionAnswer.ts | 2 +- .../entities/record/RecordCriteria.test.ts | 12 +- .../domain/entities/record/RecordCriteria.ts | 26 +- .../search/SearchTextCriteria.test.ts | 203 ------------ .../entities/search/SearchTextCriteria.ts | 86 ----- .../get-dataset-settings-use-case.ts | 23 -- .../v1/domain/usecases/get-fields-use-case.ts | 22 -- .../repositories/RecordRepository.ts | 5 +- frontend/v1/infrastructure/types/record.ts | 1 - pyproject.toml | 6 +- src/argilla/_version.py | 2 +- src/argilla/client/client.py | 1 - 52 files changed, 515 insertions(+), 1035 deletions(-) rename frontend/components/commons/user/user-settings/{UserSettingsContent.vue => LeftUserSettings.content.vue} (70%) rename frontend/components/commons/user/user-settings/{UserSettingsHeader.vue => TopUserSettings.content.vue} (83%) create mode 100644 frontend/components/feedback-task/header/SearchBar.base.vue delete mode 100644 frontend/components/feedback-task/header/search-bar-filter/SearchBarFilter.vue create mode 100644 frontend/layouts/HeaderAndOneColumn.vue create mode 100644 frontend/layouts/HeaderAndTopAndTwoColumns.vue delete mode 100644 frontend/layouts/InternalPage.vue delete mode 100644 frontend/v1/domain/entities/search/SearchTextCriteria.test.ts delete mode 100644 frontend/v1/domain/entities/search/SearchTextCriteria.ts delete mode 100644 frontend/v1/domain/usecases/get-fields-use-case.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index c8a920268b..889955f672 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,10 +35,6 @@ These are the section headers that we use: - Fixed Korean character reversed. ([#4753](https://github.com/argilla-io/argilla/pull/4753)) -### Fixed - -- Fixed requirements for version of wrapt library conflicting with Python 3.11 ([#4693](https://github.com/argilla-io/argilla/pull/4693)) - ## [1.27.0](https://github.com/argilla-io/argilla/compare/v1.26.1...v1.27.0) ### Added diff --git a/environment_dev.yml b/environment_dev.yml index c86d865a89..bfb4ecc92b 100644 --- a/environment_dev.yml +++ b/environment_dev.yml @@ -68,6 +68,6 @@ dependencies: - nltk < 4.0.0 - httpx~=0.26.0 # For now we can just install argilla-server from the GitHub repo - - git+https://github.com/argilla-io/argilla-server.git + - git+https://github.com/argilla-io/argilla-server.git@v1.28.0 # install Argilla in editable mode - -e .[listeners] diff --git a/frontend/components/base/base-range/BaseRangeSlider.vue b/frontend/components/base/base-range/BaseRangeSlider.vue index ec06c9bd10..5d6cd143a3 100644 --- a/frontend/components/base/base-range/BaseRangeSlider.vue +++ b/frontend/components/base/base-range/BaseRangeSlider.vue @@ -2,6 +2,7 @@ <div> <label :for="id"><slot /></label> <div class="range__wrapper"> + <span class="range__legend" v-text="min" /> <div class="range"> <span class="range__progress-value" ref="progress" v-text="range" /> <input @@ -14,10 +15,7 @@ v-model.number="range" /> </div> - <div class="range__legends"> - <span v-text="min" /> - <span v-text="max" /> - </div> + <span class="range__legend" v-text="max" /> </div> </div> </template> @@ -67,7 +65,7 @@ export default { this.$refs.progress.style.left = `calc(${this.progress}% + (${ 8 - this.progress * 0.15 }px))`; - this.$refs.slider.style.background = `linear-gradient(to right, #3e5cc9 ${this.progress}%, rgba(0, 0, 0, 0.2) ${this.progress}%)`; + this.$refs.slider.style.background = `linear-gradient(to right, #3e5cc9 ${this.progress}%, #ccc ${this.progress}%)`; }, }, created() { @@ -78,9 +76,6 @@ export default { }; </script> <style lang="scss" scoped> -$slider-color: $primary-color; -$slider-light-color: rgba(0, 26, 255, 0.1); -$slider-thumb-size: 16px; label { width: fit-content; height: 14px; @@ -93,38 +88,22 @@ label { min-width: 240px; &__wrapper { display: flex; - flex-direction: column; + gap: $base-space; align-items: center; margin-top: $base-space; } - &__legends { - display: flex; - width: 100%; - justify-content: space-between; + &__legend { color: $black-37; @include font-size(12px); } &__progress-value { - display: none; position: absolute; top: $base-space * 3; - margin-left: -15px; - width: 30px; + margin-left: -20px; + width: 40px; text-align: center; - color: palette(white); - background: palette(grey, 200); - border-radius: $border-radius-s; + color: $black-54; @include font-size(12px); - &:before { - position: absolute; - left: calc(50% - 6px); - top: 0; - transform: translateY(-50%); - @include triangle(top, 6px, 6px, palette(grey, 200)); - } - .range:hover & { - display: block; - } } &__slider { -webkit-appearance: none; @@ -141,39 +120,39 @@ label { input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; - height: $slider-thumb-size; - width: $slider-thumb-size; - background-color: $slider-color; + height: 15px; + width: 15px; + background-color: $primary-color; border-radius: 50%; border: none; transition: 0.2s ease-in-out; } input[type="range"]::-moz-range-thumb { - height: $slider-thumb-size; - width: $slider-thumb-size; - background-color: $slider-color; + height: 15px; + width: 15px; + background-color: $primary-color; border-radius: 50%; border: none; transition: 0.2s ease-in-out; } input[type="range"]::-webkit-slider-thumb:hover { - box-shadow: 0 0 0 4px $slider-light-color; + box-shadow: 0 0 0 6px rgba(0, 26, 255, 0.1); } input[type="range"]:active::-webkit-slider-thumb { - box-shadow: 0 0 0 6px $slider-light-color; + box-shadow: 0 0 0 10px rgba(0, 26, 255, 0.1); } input[type="range"]:focus::-webkit-slider-thumb { - box-shadow: 0 0 0 6px $slider-light-color; + box-shadow: 0 0 0 10px rgba(0, 26, 255, 0.1); } input[type="range"]::-moz-range-thumb:hover { - box-shadow: 0 0 0 4px $slider-light-color; + box-shadow: 0 0 0 6px rgba(0, 26, 255, 0.1); } input[type="range"]:active::-moz-range-thumb { - box-shadow: 0 0 0 6px $slider-light-color; + box-shadow: 0 0 0 10px rgba(0, 26, 255, 0.1); } input[type="range"]:focus::-moz-range-thumb { - box-shadow: 0 0 0 6px $slider-light-color; + box-shadow: 0 0 0 10px rgba(0, 26, 255, 0.1); } </style> diff --git a/frontend/components/base/base-switch/BaseSwitch.vue b/frontend/components/base/base-switch/BaseSwitch.vue index 1a26777757..a8a33da627 100644 --- a/frontend/components/base/base-switch/BaseSwitch.vue +++ b/frontend/components/base/base-switch/BaseSwitch.vue @@ -34,7 +34,7 @@ tabindex="-1" /> <button :type="type" class="re-switch-holder"> - <svgicon width="10" height="10" name="check" color="white"></svgicon> + <svgicon width="12" height="12" name="check" color="white"></svgicon> </button> </div> </div> @@ -42,7 +42,7 @@ </template> <script> -const checkedPosition = 70; +const checkedPosition = 50; const initialPosition = "-1px"; import "assets/icons/check"; @@ -117,9 +117,10 @@ export default { </script> <style lang="scss" scoped> -$switch-width: 28px; +$switch-width: 36px; $switch-height: 11px; -$switch-thumb-size: 18px; +$switch-thumb-size: 24px; +$switch-ripple-size: 44px; .re-switch { display: flex; align-items: center; @@ -129,13 +130,11 @@ $switch-thumb-size: 18px; display: none; } .re-switch-thumb { - background-color: #f0f0f0 !important; + background-color: palette(white) !important; } } &.disable-action { opacity: 0.5; - pointer-events: none; - cursor: default; .re-switch-thumb { background-color: palette(white) !important; transform: translate3d(-1px, -50%, 0px) !important; @@ -152,9 +151,9 @@ $switch-thumb-size: 18px; position: relative; border-radius: $switch-height; transition: $swift-ease-out; - background-color: $black-20; - cursor: pointer; + background-color: palette(grey, 600); .re-switch-thumb { + box-shadow: $shadow; width: $switch-thumb-size; height: $switch-thumb-size; position: absolute; @@ -170,14 +169,13 @@ $switch-thumb-size: 18px; } .re-switch-holder { @include absoluteCenter; - width: $switch-thumb-size; - height: $switch-thumb-size; + width: 40px; + height: 40px; margin: 0; padding: 0; z-index: 2; background: none; border: none; - cursor: pointer; &:focus { outline: none; } @@ -188,4 +186,16 @@ $switch-thumb-size: 18px; color: $black-54; } } + +.re-switch.re-dragging { + .re-switch-thumb { + cursor: grabbing; + } +} + +.re-switch.re-disabled { + .re-switch-thumb { + cursor: default; + } +} </style> diff --git a/frontend/components/base/base-table/BaseTableInfo.vue b/frontend/components/base/base-table/BaseTableInfo.vue index 3f3d921ca8..16c88fd7d9 100644 --- a/frontend/components/base/base-table/BaseTableInfo.vue +++ b/frontend/components/base/base-table/BaseTableInfo.vue @@ -447,7 +447,6 @@ export default { &__body { overflow: auto; padding-bottom: 0.5em; - min-height: 250px; @extend %hide-scrollbar; #{$this}__item { margin-bottom: -1px; diff --git a/frontend/components/commons/user/user-settings/UserSettingsContent.vue b/frontend/components/commons/user/user-settings/LeftUserSettings.content.vue similarity index 70% rename from frontend/components/commons/user/user-settings/UserSettingsContent.vue rename to frontend/components/commons/user/user-settings/LeftUserSettings.content.vue index b2e1cf9f6a..9b422209df 100644 --- a/frontend/components/commons/user/user-settings/UserSettingsContent.vue +++ b/frontend/components/commons/user/user-settings/LeftUserSettings.content.vue @@ -2,11 +2,11 @@ <div class="wrapper"> <BaseSpinner v-if="!user" /> - <div class="user-settings" v-if="user"> - <div class="user-settings-item edition-user-info-component"> + <div class="left-content" v-if="user"> + <div class="left-content-item edition-user-info-component"> <EditionUserInfoComponent :userInfo="user" /> </div> - <div class="user-settings-item user-token-component"> + <div class="left-content-item user-token-component"> <UserTokenComponent :userToken="user.api_key" /> </div> </div> @@ -25,7 +25,7 @@ export default { </script> <style lang="scss" scoped> -.user-settings-item { +.left-content-item { border-bottom: 1px solid $black-10; } </style> diff --git a/frontend/components/commons/user/user-settings/UserSettingsHeader.vue b/frontend/components/commons/user/user-settings/TopUserSettings.content.vue similarity index 83% rename from frontend/components/commons/user/user-settings/UserSettingsHeader.vue rename to frontend/components/commons/user/user-settings/TopUserSettings.content.vue index 7b32301784..8d66f38337 100644 --- a/frontend/components/commons/user/user-settings/UserSettingsHeader.vue +++ b/frontend/components/commons/user/user-settings/TopUserSettings.content.vue @@ -1,5 +1,5 @@ <template> - <div class="user-settings__header"> + <div class="top-content"> <h1 v-text="$t('userSettings.title')" /> <BaseButton :to="datasetsURL" class="secondary text"> <svgicon name="chevron-left" width="10" height="10" color="#4C4EA3" /> @@ -20,13 +20,11 @@ export default { </script> <style lang="scss" scoped> -.user-settings__header { +.top-content { display: flex; justify-content: space-between; align-items: center; + height: 100%; border-bottom: 1px solid #e6e6e6; - @include media(">tablet") { - min-height: 100px; - } } </style> diff --git a/frontend/components/features/datasets/datasets-settings/LeftDatasetSettings.content.vue b/frontend/components/features/datasets/datasets-settings/LeftDatasetSettings.content.vue index 28e499808d..5a22a7fa03 100644 --- a/frontend/components/features/datasets/datasets-settings/LeftDatasetSettings.content.vue +++ b/frontend/components/features/datasets/datasets-settings/LeftDatasetSettings.content.vue @@ -112,7 +112,6 @@ export default { display: flex; flex-direction: column; gap: 10px; - max-width: 800px; .dataset-description { display: flex; align-items: center; diff --git a/frontend/components/features/datasets/datasets-settings/TopDatasetSettings.content.vue b/frontend/components/features/datasets/datasets-settings/TopDatasetSettings.content.vue index cf447545bd..6a7be4df9a 100644 --- a/frontend/components/features/datasets/datasets-settings/TopDatasetSettings.content.vue +++ b/frontend/components/features/datasets/datasets-settings/TopDatasetSettings.content.vue @@ -45,8 +45,5 @@ export default { align-items: center; height: 100%; border-bottom: 1px solid #e6e6e6; - @include media(">tablet") { - min-height: 100px; - } } </style> diff --git a/frontend/components/features/datasets/datasets-table/dataset-progress/DatasetProgress.vue b/frontend/components/features/datasets/datasets-table/dataset-progress/DatasetProgress.vue index fba1a014c6..6597827213 100644 --- a/frontend/components/features/datasets/datasets-table/dataset-progress/DatasetProgress.vue +++ b/frontend/components/features/datasets/datasets-table/dataset-progress/DatasetProgress.vue @@ -35,13 +35,11 @@ export default { <style lang="scss" scoped> .dataset-progress { - position: relative; display: flex; flex-direction: column; align-items: flex-start; gap: calc($base-space / 2); max-width: 160px; - z-index: 0; &__bar { width: 100%; max-width: 160px; diff --git a/frontend/components/feedback-task/container/fields/span-annotation/SpanAnnotationTextField.component.vue b/frontend/components/feedback-task/container/fields/span-annotation/SpanAnnotationTextField.component.vue index a2dca91c82..8486a26648 100644 --- a/frontend/components/feedback-task/container/fields/span-annotation/SpanAnnotationTextField.component.vue +++ b/frontend/components/feedback-task/container/fields/span-annotation/SpanAnnotationTextField.component.vue @@ -239,7 +239,7 @@ export default { &__field { position: relative; margin: 0; - @include font-size(16px); + @include font-size(18px); line-height: v-bind(lineHeight); user-select: text; &--overlapped { diff --git a/frontend/components/feedback-task/container/fields/span-annotation/components/EntityComponent.vue b/frontend/components/feedback-task/container/fields/span-annotation/components/EntityComponent.vue index 045cf9f22b..353ab84e72 100644 --- a/frontend/components/feedback-task/container/fields/span-annotation/components/EntityComponent.vue +++ b/frontend/components/feedback-task/container/fields/span-annotation/components/EntityComponent.vue @@ -129,7 +129,7 @@ export default { return this.options.length === 1; }, suggestedScore() { - return this.suggestion?.value.score?.fixed; + return this.suggestion?.value.score.fixed; }, entityColor() { return this.entity.color; @@ -313,7 +313,6 @@ export default { } &__suggestion { margin-right: calc($base-space / 2); - flex-shrink: 0; &--score { display: none; margin-right: calc($base-space / 2); diff --git a/frontend/components/feedback-task/container/fields/span-annotation/components/EntityDropdown.vue b/frontend/components/feedback-task/container/fields/span-annotation/components/EntityDropdown.vue index c5ad0ed183..9fa0ec1f9c 100644 --- a/frontend/components/feedback-task/container/fields/span-annotation/components/EntityDropdown.vue +++ b/frontend/components/feedback-task/container/fields/span-annotation/components/EntityDropdown.vue @@ -16,7 +16,7 @@ class="span-entity__input" type="text" autocomplete="off" - placeholder="" + :placeholder="$nuxt.$t('search')" autofocus v-model="searchText" @keydown.stop="" diff --git a/frontend/components/feedback-task/container/fields/span-annotation/components/highlighting.ts b/frontend/components/feedback-task/container/fields/span-annotation/components/highlighting.ts index 994ce7e58f..8d8b5f1d17 100644 --- a/frontend/components/feedback-task/container/fields/span-annotation/components/highlighting.ts +++ b/frontend/components/feedback-task/container/fields/span-annotation/components/highlighting.ts @@ -73,7 +73,7 @@ export class Highlighting { ) { this.styles = { entitiesGap: 16, - lineHeight: config.allowOverlap ? 48 : 32, + lineHeight: 32, spanContainerId: `entity-span-container-${nodeId}`, entityCssKey: "hl", ...styles, @@ -171,10 +171,8 @@ export class Highlighting { ); const lineHeight = - maxOverlappedLevels > 2 - ? this.styles.lineHeight + - this.styles.entitiesGap * Math.max(0, maxOverlappedLevels - 2) - : this.styles.lineHeight; + this.styles.lineHeight + + this.styles.entitiesGap * Math.max(0, maxOverlappedLevels - 1); this.config.lineHeight = lineHeight; } diff --git a/frontend/components/feedback-task/container/questions/form/ranking/drag-and-drop-selection/DndSelection.component.vue b/frontend/components/feedback-task/container/questions/form/ranking/drag-and-drop-selection/DndSelection.component.vue index d362b862b8..ca98b5cda7 100644 --- a/frontend/components/feedback-task/container/questions/form/ranking/drag-and-drop-selection/DndSelection.component.vue +++ b/frontend/components/feedback-task/container/questions/form/ranking/drag-and-drop-selection/DndSelection.component.vue @@ -17,8 +17,9 @@ @focus="onFocus" > <BaseTooltip + v-if="isSuggested(item)" class="draggable__rank-card--unranked" - :title="isSuggested(item) ? $t('suggestion.name') : null" + :title="$t('suggestion.name')" :text="getSuggestedAgent(item)" minimalist > @@ -68,7 +69,8 @@ @focus="onFocus" > <BaseTooltip - :title="isSuggested(item) ? $t('suggestion.name') : null" + v-if="isSuggested(item)" + :title="$t('suggestion.name')" :text="getSuggestedAgent(item)" minimalist class="draggable__rank-card--ranked" diff --git a/frontend/components/feedback-task/container/questions/form/shared-components/label-selection/LabelSelection.component.vue b/frontend/components/feedback-task/container/questions/form/shared-components/label-selection/LabelSelection.component.vue index 6859c04fe6..89566ea2e0 100644 --- a/frontend/components/feedback-task/container/questions/form/shared-components/label-selection/LabelSelection.component.vue +++ b/frontend/components/feedback-task/container/questions/form/shared-components/label-selection/LabelSelection.component.vue @@ -181,39 +181,46 @@ export default { .includes(this.searchInput.toLowerCase()) ); }, + remainingVisibleOptions() { + return this.filteredOptions + .slice(this.maxOptionsToShowBeforeCollapse) + .filter((option) => option.isSelected); + }, visibleOptions() { - let options = this.filteredOptions; - - if (this.suggestionFirst) { - const suggestedOptions = this.filteredOptions - .filter( - (v) => this.suggestion && this.suggestion.isSuggested(v.value) - ) - .sort((a, b) => { - const isASuggested = this.suggestion.getSuggestion(a.value); - const isBSuggested = this.suggestion.getSuggestion(b.value); - - return isASuggested?.score > isBSuggested?.score ? -1 : 1; - }); + if (!this.suggestionFirst) { + if (this.isExpanded) return this.filteredOptions; - const noSuggestedOptions = this.filteredOptions.filter( - (v) => !this.suggestion || !this.suggestion.isSuggested(v.value) - ); - - options = [...suggestedOptions, ...noSuggestedOptions]; + return this.filteredOptions + .slice(0, this.maxOptionsToShowBeforeCollapse) + .concat(this.remainingVisibleOptions); } + const suggestedOptions = this.filteredOptions + .filter((v) => this.suggestion && this.suggestion.isSuggested(v.value)) + .sort((a, b) => { + const isASuggested = this.suggestion.getSuggestion(a.value); + const isBSuggested = this.suggestion.getSuggestion(b.value); + + return isASuggested?.score > isBSuggested?.score ? -1 : 1; + }); + + const noSuggestedOptions = this.filteredOptions.filter( + (v) => !this.suggestion || !this.suggestion.isSuggested(v.value) + ); + if (this.isExpanded) { - return options; + return [...suggestedOptions, ...noSuggestedOptions]; } - const remainingSorted = options - .slice(this.maxOptionsToShowBeforeCollapse) - .filter((option) => option.isSelected); + const options = [ + ...suggestedOptions.filter((o) => o.isSelected), + ...noSuggestedOptions.filter((o) => o.isSelected), + ]; - return options - .slice(0, this.maxOptionsToShowBeforeCollapse) - .concat(remainingSorted); + return options.slice( + 0, + Math.max(options.length, this.maxOptionsToShowBeforeCollapse) + ); }, numberToShowInTheCollapseButton() { return this.filteredOptions.length - this.visibleOptions.length; @@ -433,6 +440,9 @@ $label-dark-color: palette(purple, 200); overflow: hidden; text-overflow: ellipsis; min-width: 0; + &:hover { + direction: rtl; + } } &__suggestion { display: flex; @@ -497,9 +507,8 @@ input[type="checkbox"] { align-items: center; justify-content: center; flex-shrink: 0; - min-width: 12px; - padding: 2px; - line-height: 1; + height: $base-space * 2; + aspect-ratio: 1; border-radius: $border-radius; border-width: 1px 1px 3px 1px; border-color: $black-20; diff --git a/frontend/components/feedback-task/container/questions/form/span/EntityLabelBadge.vue b/frontend/components/feedback-task/container/questions/form/span/EntityLabelBadge.vue index bcec2123ea..788e839a7a 100644 --- a/frontend/components/feedback-task/container/questions/form/span/EntityLabelBadge.vue +++ b/frontend/components/feedback-task/container/questions/form/span/EntityLabelBadge.vue @@ -104,6 +104,9 @@ input[type="checkbox"] { overflow: hidden; text-overflow: ellipsis; min-width: 0; + &:hover { + direction: rtl; + } } &:not(.label-active):hover { background: v-bind(optionLightColor); diff --git a/frontend/components/feedback-task/header/DatasetFilters.component.vue b/frontend/components/feedback-task/header/DatasetFilters.component.vue index c17c4e591c..85455f6e13 100644 --- a/frontend/components/feedback-task/header/DatasetFilters.component.vue +++ b/frontend/components/feedback-task/header/DatasetFilters.component.vue @@ -1,9 +1,9 @@ <template> <div class="filters__wrapper"> <div class="filters"> - <SearchBarFilter + <SearchBarBase v-model="recordCriteria.searchText" - :fields="datasetFields" + :placeholder="'Introduce a query'" /> <StatusFilter class="filters__status" v-model="recordCriteria.status" /> <FilterButton @@ -40,8 +40,8 @@ v-model="recordCriteria.metadata.value" /> <ResponsesFilter - :datasetQuestions="datasetQuestions" v-model="recordCriteria.response.value" + :datasetQuestions="datasetQuestions" /> <SuggestionFilter v-model="recordCriteria.suggestion.value" @@ -102,7 +102,7 @@ export default { }, }, watch: { - "recordCriteria.searchText.value"() { + "recordCriteria.searchText"() { this.newFiltersChanged(); }, "recordCriteria.status"() { diff --git a/frontend/components/feedback-task/header/SearchBar.base.vue b/frontend/components/feedback-task/header/SearchBar.base.vue new file mode 100644 index 0000000000..c502e0b027 --- /dev/null +++ b/frontend/components/feedback-task/header/SearchBar.base.vue @@ -0,0 +1,174 @@ +<!-- + - coding=utf-8 + - Copyright 2021-present, the Recognai S.L. team. + - + - Licensed under the Apache License, Version 2.0 (the "License"); + - you may not use this file except in compliance with the License. + - You may obtain a copy of the License at + - + - http://www.apache.org/licenses/LICENSE-2.0 + - + - Unless required by applicable law or agreed to in writing, software + - distributed under the License is distributed on an "AS IS" BASIS, + - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + - See the License for the specific language governing permissions and + - limitations under the License. + --> + +<template> + <div + class="search-area" + :class="{ active: isSearchActive, expanded: isExpanded }" + > + <BaseButton + @on-click="applySearch" + class="search-area__icon --search" + :data-title="$t('search')" + > + <svgicon name="search" width="16" height="16" /> + </BaseButton> + <input + ref="searchRef" + class="search-area__input" + type="text" + v-model.trim="searchValue" + :placeholder="placeholder" + :aria-description="description" + autocomplete="off" + @keydown.stop="" + @keypress.enter.stop="applySearch" + /> + <BaseButton + @on-click="resetValue" + v-if="showDelete" + class="search-area__icon --close" + > + <svgicon name="close" width="12" height="12" /> + </BaseButton> + </div> +</template> + +<script> +import { isNil } from "lodash"; + +export default { + name: "SearchBarComponent", + props: { + value: { + type: String, + default: "", + }, + placeholder: { + type: String, + default: "", + }, + description: { + type: String, + default: "Introduce a text", + }, + }, + data() { + return { + searchValue: "", + localAdditionalInfo: "", + isExpanded: false, + }; + }, + computed: { + isSearchActive() { + return !(isNil(this.value) || this.value.length === 0); + }, + isSearchValueEmpty() { + return isNil(this.searchValue) || this.searchValue.length === 0; + }, + showDelete() { + return !this.isSearchValueEmpty || this.isSearchActive; + }, + }, + watch: { + value: { + immediate: true, + handler(newValue) { + this.searchValue = newValue; + }, + }, + }, + methods: { + applySearch() { + this.$emit("input", this.searchValue); + if (this.isSearchValueEmpty) { + this.isExpanded = !this.isExpanded; + this.$refs.searchRef.focus(); + } else { + this.collapseSearch(); + this.$refs.searchRef.blur(); + } + }, + resetValue() { + this.searchValue = ""; + this.$emit("input", ""); + this.collapseSearch(); + }, + collapseSearch() { + this.isExpanded = false; + }, + }, +}; +</script> + +<style lang="scss" scoped> +$searchBarSize: $base-space * 4; +.search-area { + display: flex; + align-items: center; + gap: $base-space; + padding: 7px; + max-height: $searchBarSize; + max-width: $searchBarSize; + border-radius: $border-radius-l; + transition: all 0.3s ease; + border: 1px solid transparent; + &:hover { + background: $black-4; + transition: all 0.3s ease; + } + &.active, + &.expanded { + background: palette(white); + border: 1px solid $black-10; + transition: all 0.3s ease; + .button.--search { + color: $black-37; + } + } + &.active, + &.expanded { + max-width: 100%; + } + &.expanded:focus-within, + &.active { + border: 1px solid $primary-color; + } + &__icon.button { + display: flex; + flex-shrink: 0; + padding: 0; + color: $black-54; + } + &__input { + width: 100%; + padding: 0; + border: none; + outline: 0; + background: none; + line-height: 1.4; + @include input-placeholder { + color: $black-37; + } + } +} +.button[data-title] { + overflow: visible; + @include tooltip-mini("top", 16px); +} +</style> diff --git a/frontend/components/feedback-task/header/search-bar-filter/SearchBarFilter.vue b/frontend/components/feedback-task/header/search-bar-filter/SearchBarFilter.vue deleted file mode 100644 index b22744f657..0000000000 --- a/frontend/components/feedback-task/header/search-bar-filter/SearchBarFilter.vue +++ /dev/null @@ -1,300 +0,0 @@ -<!-- - - coding=utf-8 - - Copyright 2021-present, the Recognai S.L. team. - - - - Licensed under the Apache License, Version 2.0 (the "License"); - - you may not use this file except in compliance with the License. - - You may obtain a copy of the License at - - - - http://www.apache.org/licenses/LICENSE-2.0 - - - - Unless required by applicable law or agreed to in writing, software - - distributed under the License is distributed on an "AS IS" BASIS, - - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - - See the License for the specific language governing permissions and - - limitations under the License. - --> - -<template> - <div - class="search-area" - :class="{ active: isSearchActive, expanded: isExpanded }" - > - <BaseButton - @on-click="openOrApply" - class="search-area__icon --search" - :data-title="$t('search')" - > - <svgicon name="search" width="16" height="16" /> - </BaseButton> - <input - ref="searchRef" - class="search-area__input" - type="text" - v-model.trim="searchValue" - :placeholder="$t('searchPlaceholder')" - :aria-description="$t('searchPlaceholder')" - autocomplete="off" - @keydown.stop="" - @keypress.enter.stop="applySearch" - /> - <BaseButton - @on-click="resetValue" - v-if="showDelete" - class="search-area__icon --close" - > - <svgicon name="close" width="12" height="12" /> - </BaseButton> - - <BaseDropdown - v-if="fields.length > 1" - class="search-area__fields" - :visible="dropdownIsVisible" - @visibility="onVisibility" - > - <template slot="dropdown-header"> - <span class="search-area__fields__header"> - <span class="search-area__fields__header__text">{{ - selectedField.title - }}</span> - <svgicon name="chevron-down" height="8" /> - </span> - </template> - <template slot="dropdown-content"> - <ul class="search-area__fields__content"> - <li v-for="field in filteredFields" :key="field.id"> - <BaseButton @on-click="selectField(field)">{{ - field.title - }}</BaseButton> - </li> - </ul> - </template> - </BaseDropdown> - </div> -</template> - -<script> -export default { - name: "SearchBarFilter", - props: { - value: { - type: Object, - required: true, - }, - fields: { - type: Array, - default: () => [], - }, - }, - data() { - return { - searchValue: "", - isExpanded: false, - dropdownIsVisible: false, - }; - }, - computed: { - isSearchActive() { - return this.searchValue.length > 0 || this.value.isCompleted; - }, - showDelete() { - return this.isSearchActive; - }, - selectedField() { - return this.fieldList.find( - (field) => field.name === this.value.value.field - ); - }, - fieldList() { - return [ - { - id: "all", - name: "all", - title: this.$t("all"), - }, - ...this.fields, - ]; - }, - filteredFields() { - return this.fieldList.filter( - (field) => field.name !== this.value.value.field - ); - }, - }, - watch: { - value: { - immediate: true, - deep: true, - handler(newValue) { - this.searchValue = newValue.value.text; - }, - }, - }, - methods: { - openOrApply() { - if (this.isExpanded && this.isSearchActive) { - this.applySearch(); - } else { - this.isExpanded = !this.isExpanded; - - if (this.isExpanded) { - this.$refs.searchRef.focus(); - } else { - this.$refs.searchRef.blur(); - } - } - }, - applySearch() { - if (!this.isSearchActive) return; - - this.value.value = { - ...this.value.value, - text: this.searchValue, - field: this.value.value.field, - }; - - this.$refs.searchRef.blur(); - }, - resetValue() { - this.collapseSearch(); - - this.value.reset(); - }, - collapseSearch() { - this.isExpanded = false; - }, - onVisibility(value) { - this.dropdownIsVisible = value; - }, - selectField(field) { - this.value.value.field = field.name; - this.dropdownIsVisible = false; - - this.applySearch(); - }, - }, -}; -</script> - -<style lang="scss" scoped> -$searchBarSize: $base-space * 4; -.search-area { - display: flex; - align-items: center; - gap: $base-space; - max-height: $searchBarSize; - max-width: $searchBarSize; - border-radius: $border-radius-l; - transition: all 0.3s ease; - border: 1px solid transparent; - &.active, - &.expanded { - background: palette(white); - border: 1px solid $black-10; - transition: all 0.3s ease; - .button.--search { - color: $black-37; - } - } - &.active, - &.expanded { - max-width: 100%; - .search-area__fields { - display: block; - } - } - &.expanded:focus-within, - &.active { - border: 1px solid $primary-color; - } - &__icon.button { - display: flex; - flex-shrink: 0; - padding: $base-space; - color: $black-54; - &.--search { - border-radius: $border-radius-l; - &:hover { - background: $black-4; - color: $black-54; - transition: all 0.3s ease; - } - } - } - &__input { - width: 100%; - padding: 0; - border: none; - outline: 0; - background: none; - line-height: 1.4; - @include input-placeholder { - color: $black-37; - } - } - &__fields { - display: none; - max-width: 30%; - border-left: 1px solid $black-37; - flex-shrink: 0; - &__header { - display: flex; - gap: $base-space; - align-items: center; - padding-inline: $base-space; - min-width: 0; - line-height: 1em; - &__text { - font-weight: 500; - @include truncate; - } - &:hover { - cursor: pointer; - color: $black-87; - } - .svg-icon { - flex-shrink: 0; - } - } - &__content { - list-style: none; - padding: $base-space; - margin: 0; - li { - padding: $base-space; - border-radius: $border-radius-s; - transition: background-color 0.3s ease; - &:hover { - background: $black-4; - cursor: pointer; - transition: background-color 0.3s ease; - } - } - .button { - display: block; - max-width: 200px; - text-align: left; - padding: 0; - font-weight: normal; - @include truncate; - } - } - :deep(.dropdown__content) { - min-width: 100%; - left: auto; - right: 0; - top: calc(100% + $base-space * 2); - } - :deep(.dropdown__header) { - &:hover, - &:focus { - background: none; - } - } - } -} -.button[data-title] { - overflow: visible; - @include tooltip-mini("top", 8px); -} -</style> diff --git a/frontend/components/feedback-task/header/useDatasetsFiltersViewModel.ts b/frontend/components/feedback-task/header/useDatasetsFiltersViewModel.ts index b7736b2f8f..8a659b2d41 100644 --- a/frontend/components/feedback-task/header/useDatasetsFiltersViewModel.ts +++ b/frontend/components/feedback-task/header/useDatasetsFiltersViewModel.ts @@ -1,26 +1,24 @@ import { useResolve } from "ts-injecty"; import { onBeforeMount, ref } from "vue-demi"; -import { Field } from "~/v1/domain/entities/field/Field"; import { Metadata } from "~/v1/domain/entities/metadata/Metadata"; import { Question } from "~/v1/domain/entities/question/Question"; import { RecordCriteria } from "~/v1/domain/entities/record/RecordCriteria"; import { GetDatasetQuestionsFilterUseCase } from "~/v1/domain/usecases/get-dataset-questions-filter-use-case"; -import { GetFieldsUseCase } from "~/v1/domain/usecases/get-fields-use-case"; import { GetMetadataUseCase } from "~/v1/domain/usecases/get-metadata-use-case"; +import { useRecords } from "~/v1/infrastructure/storage/RecordsStorage"; export const useDatasetsFiltersViewModel = ({ recordCriteria, }: { recordCriteria: RecordCriteria; }) => { + const { state: records } = useRecords(); const datasetMetadataIsLoaded = ref(false); const datasetQuestionIsLoaded = ref(false); const datasetMetadata = ref<Metadata[]>([]); const datasetQuestions = ref<Question[]>([]); - const datasetFields = ref<Field[]>([]); const getMetadataUseCase = useResolve(GetMetadataUseCase); const getQuestionsUseCase = useResolve(GetDatasetQuestionsFilterUseCase); - const getFieldsUseCase = useResolve(GetFieldsUseCase); const loadMetadata = async () => { try { @@ -42,25 +40,16 @@ export const useDatasetsFiltersViewModel = ({ } }; - const loadFields = async () => { - try { - datasetFields.value = await getFieldsUseCase.execute( - recordCriteria.datasetId - ); - } catch {} - }; - onBeforeMount(() => { loadMetadata(); loadQuestions(); - loadFields(); }); return { + records, datasetMetadataIsLoaded, datasetQuestionIsLoaded, datasetMetadata, datasetQuestions, - datasetFields, }; }; diff --git a/frontend/components/feedback-task/settings/SettingsDangerZone.vue b/frontend/components/feedback-task/settings/SettingsDangerZone.vue index ba384507f3..5d01ce7288 100644 --- a/frontend/components/feedback-task/settings/SettingsDangerZone.vue +++ b/frontend/components/feedback-task/settings/SettingsDangerZone.vue @@ -32,7 +32,7 @@ export default { &__content { flex: 1; - max-width: 800px; + max-width: 1000px; padding-top: $base-space; } } diff --git a/frontend/components/feedback-task/settings/SettingsFields.vue b/frontend/components/feedback-task/settings/SettingsFields.vue index ab3e08e76c..462d7ca63c 100644 --- a/frontend/components/feedback-task/settings/SettingsFields.vue +++ b/frontend/components/feedback-task/settings/SettingsFields.vue @@ -19,11 +19,9 @@ <input type="text" id="field.id" v-model="field.title" /> </Validation> - <BaseSwitch - class="settings__edition-form__switch" - v-model="field.settings.use_markdown" - >{{ $t("useMarkdown") }}</BaseSwitch - > + <BaseSwitch v-model="field.settings.use_markdown">{{ + $t("useMarkdown") + }}</BaseSwitch> <div class="settings__edition-form__footer"> <BaseButton @@ -85,7 +83,7 @@ export default { flex: 1; flex-direction: column; gap: $base-space * 2; - max-width: 800px; + max-width: 1000px; padding-top: $base-space; &__fields { @@ -109,12 +107,12 @@ export default { display: flex; flex-direction: column; width: 100%; - gap: 12px; + gap: $base-space; & label { width: fit-content; height: 14px; - color: $black-87; + color: $black-54; } & input { @@ -134,14 +132,6 @@ export default { } } - &__switch { - @include media(">desktop") { - :deep(label) { - min-width: 140px; - } - } - } - &__footer { width: 100%; flex-direction: row; diff --git a/frontend/components/feedback-task/settings/SettingsInfo.vue b/frontend/components/feedback-task/settings/SettingsInfo.vue index 5b347574d1..2e0718e5ba 100644 --- a/frontend/components/feedback-task/settings/SettingsInfo.vue +++ b/frontend/components/feedback-task/settings/SettingsInfo.vue @@ -94,11 +94,11 @@ export default { &__content { flex: 1; - max-width: 800px; + max-width: 1000px; padding-top: $base-space; } &__area { - max-width: 800px; + max-width: 1000px; padding-bottom: $base-space * 3; border-bottom: 1px solid $black-10; } diff --git a/frontend/components/feedback-task/settings/SettingsInfoReadOnly.vue b/frontend/components/feedback-task/settings/SettingsInfoReadOnly.vue index 7d13d7b1db..6b57e99958 100644 --- a/frontend/components/feedback-task/settings/SettingsInfoReadOnly.vue +++ b/frontend/components/feedback-task/settings/SettingsInfoReadOnly.vue @@ -56,7 +56,7 @@ export default { <styles lang="scss" scoped> .settings { &__area { - max-width: 800px; + max-width: 1000px; padding-bottom: $base-space * 3; border-bottom: 1px solid $black-10; } diff --git a/frontend/components/feedback-task/settings/SettingsMetadata.vue b/frontend/components/feedback-task/settings/SettingsMetadata.vue index f919b71ebf..df5cb378fe 100644 --- a/frontend/components/feedback-task/settings/SettingsMetadata.vue +++ b/frontend/components/feedback-task/settings/SettingsMetadata.vue @@ -20,11 +20,9 @@ <input type="text" id="metadata.title" v-model="metadata.title" /> </Validation> - <BaseSwitch - class="settings__edition-form__switch" - v-model="metadata.visibleForAnnotators" - >{{ $t("visibleForAnnotators") }}</BaseSwitch - > + <BaseSwitch v-model="metadata.visibleForAnnotators">{{ + $t("visibleForAnnotators") + }}</BaseSwitch> <div class="settings__edition-form__footer"> <BaseButton @@ -51,11 +49,9 @@ @submit.prevent="updateDataset(settings.dataset)" class="settings__edition-form__metadata" > - <BaseSwitch - class="settings__edition-form__switch" - v-model="settings.dataset.allowExtraMetadata" - >{{ $t("allowExtraMetadata") }}</BaseSwitch - > + <BaseSwitch v-model="settings.dataset.allowExtraMetadata">{{ + $t("allowExtraMetadata") + }}</BaseSwitch> <div class="settings__edition-form__footer"> <BaseButton type="button" @@ -110,7 +106,7 @@ export default { flex: 1; flex-direction: column; gap: $base-space * 2; - max-width: 800px; + max-width: 1000px; padding-top: $base-space; &__metadata { @@ -119,12 +115,6 @@ export default { gap: $base-space * 2; } - &__switch { - display: flex; - justify-content: space-between; - max-width: 500px; - } - &__name { display: flex; flex-direction: row; @@ -143,12 +133,12 @@ export default { display: flex; flex-direction: column; width: 100%; - gap: 12px; + gap: $base-space; & label { width: fit-content; height: 14px; - color: $black-87; + color: $black-54; } & input { diff --git a/frontend/components/feedback-task/settings/SettingsQuestions.vue b/frontend/components/feedback-task/settings/SettingsQuestions.vue index 8b6751cfea..a57caaaf48 100644 --- a/frontend/components/feedback-task/settings/SettingsQuestions.vue +++ b/frontend/components/feedback-task/settings/SettingsQuestions.vue @@ -40,7 +40,7 @@ </Validation> <div - class="settings__edition-form__group --subcategories" + class="settings__edition-form__group" v-if=" question.isMultiLabelType || question.isSingleLabelType || @@ -48,28 +48,6 @@ " > <label :for="`options-${question.id}`" v-text="$t('labels')" /> - <BaseSwitch - v-if="question.isMultiLabelType" - class="settings__edition-form__switch --subcategory" - :id="`options-order-${question.id}`" - v-model="question.settings.suggestionFirst" - >{{ $t("suggestionFirst") }}</BaseSwitch - > - - <BaseRangeSlider - v-if="question.settings.shouldShowVisibleOptions" - class="settings__edition-form__slider --subcategory" - :id="`visible_options-${question.id}`" - :min="3" - :max="question.settings.options.length" - v-model="question.settings.visible_options" - >{{ $t("visibleLabels") }}</BaseRangeSlider - > - - <label - v-text="$t('order')" - class="settings__edition-form__label --subcategory" - /> <draggable class="label__container" ghost-class="label__item__ghost" @@ -95,12 +73,27 @@ <BaseSwitch v-if="question.isTextType" - class="settings__edition-form__switch" :id="`use-markdown-${question.id}`" v-model="question.settings.use_markdown" >{{ $t("useMarkdown") }}</BaseSwitch > + <BaseSwitch + v-if="question.isMultiLabelType" + :id="`options-order-${question.id}`" + v-model="question.settings.suggestionFirst" + >{{ $t("suggestionFirst") }}</BaseSwitch + > + + <BaseRangeSlider + v-if="question.settings.shouldShowVisibleOptions" + :id="`visible_options-${question.id}`" + :min="3" + :max="question.settings.options.length" + v-model="question.settings.visible_options" + >{{ $t("visibleLabels") }}</BaseRangeSlider + > + <div class="settings__edition-form__footer"> <BaseButton type="button" @@ -170,20 +163,11 @@ export default { overflow: auto; padding-right: $base-space * 2; - &__label { - &.--subcategory { - display: block; - @include font-size(13px); - color: $black-87; - } - } - &__content { display: flex; flex-direction: column; gap: $base-space * 2; width: 100%; - max-width: 800px; margin-top: $base-space; } @@ -207,70 +191,16 @@ export default { } } - &__switch.re-switch { - :deep(label) { - color: $black-87; - } - @include media(">desktop") { - :deep(label) { - min-width: 180px; - } - } - &.--subcategory { - @include font-size(13px); - } - } - - &__slider { - :deep(label) { - color: $black-87; - line-height: 1; - margin-right: 1em; - } - @include media(">desktop") { - :deep(label) { - min-width: 180px; - margin-right: 1em; - } - } - &.--subcategory { - @include font-size(13px); - @include media(">desktop") { - display: flex; - align-items: center; - } - } - } - &__group { display: flex; flex-direction: column; width: 100%; - gap: 12px; - - &.--subcategories { - & > label:first-child { - margin-bottom: $base-space * 2; - } - @include media(">desktop") { - gap: 0; - } - } - - .--subcategory { - display: flex; - flex-wrap: wrap; - align-items: center; - @include media(">desktop") { - flex-wrap: nowrap; - height: 32px; - } - } + gap: $base-space; & > label { width: fit-content; height: 14px; - color: $black-87; + color: $black-54; } & input { diff --git a/frontend/components/feedback-task/settings/SettingsVectors.vue b/frontend/components/feedback-task/settings/SettingsVectors.vue index 9b3f7947ee..1b7e81913c 100644 --- a/frontend/components/feedback-task/settings/SettingsVectors.vue +++ b/frontend/components/feedback-task/settings/SettingsVectors.vue @@ -89,7 +89,7 @@ export default { flex: 1; flex-direction: column; gap: $base-space * 2; - max-width: 800px; + max-width: 1000px; padding-top: $base-space; &__vectors { @@ -116,12 +116,12 @@ export default { display: flex; flex-direction: column; width: 100%; - gap: 12px; + gap: $base-space; & label { width: fit-content; height: 14px; - color: $black-87; + color: $black-54; } & input { diff --git a/frontend/layouts/HeaderAndOneColumn.vue b/frontend/layouts/HeaderAndOneColumn.vue new file mode 100644 index 0000000000..3ecd9c6687 --- /dev/null +++ b/frontend/layouts/HeaderAndOneColumn.vue @@ -0,0 +1,48 @@ +<template> + <div> + <div class="header"> + <slot name="header">here is the header</slot> + </div> + <main class="layout"> + <div class="empty-content-left"></div> + <div class="empty-content-right"></div> + <div class="center"> + <slot name="center">here is the left content</slot> + </div> + </main> + </div> +</template> + +<script> +export default { + name: "HeaderAndOneColumnLayout", +}; +</script> + +<style lang="scss" scoped> +.layout { + display: grid; + grid-template-columns: 56px 1fr 1fr 1fr 56px; + grid-template-rows: 0 100px 1fr 1fr 1fr; + grid-column-gap: 0px; + grid-row-gap: 0px; + overflow: auto; + height: calc(100vh - $topbarHeight); + background: palette(white); + @include media("<desktop") { + grid-template-columns: 16px 1fr 1fr 1fr 16px; + } +} +.header { + grid-area: 1 / 1 / 2 / 6; +} +.empty-content-left { + grid-area: 2 / 1 / 6 / 2; +} +.empty-content-right { + grid-area: 2 / 5 / 6 / 6; +} +.center { + grid-area: 2 / 2 / 6 / 5; +} +</style> diff --git a/frontend/layouts/HeaderAndTopAndTwoColumns.vue b/frontend/layouts/HeaderAndTopAndTwoColumns.vue new file mode 100644 index 0000000000..42f3c9af02 --- /dev/null +++ b/frontend/layouts/HeaderAndTopAndTwoColumns.vue @@ -0,0 +1,67 @@ +<template> + <div> + <div class="header"> + <slot name="header">here is the header</slot> + </div> + <main class="layout"> + <div class="empty-content-left"></div> + <div class="empty-content-right"></div> + <div class="top"> + <slot name="top">here is the top content</slot> + </div> + <div class="left"> + <slot name="left">here is the left content</slot> + </div> + <div class="right" v-if="!!this.$slots.right"> + <slot name="right">here is the right content</slot> + </div> + </main> + </div> +</template> + +<script> +export default { + name: "HeaderAndTopAndTwoColumnsLayout", +}; +</script> + +<style lang="scss" scoped> +.layout { + display: grid; + grid-template-columns: 56px 1fr 1fr 1fr 56px; + grid-template-rows: 0 100px 1fr 1fr 1fr; + grid-column-gap: 0px; + grid-row-gap: 0px; + overflow: auto; + height: calc(100vh - $topbarHeight); + background: palette(white); +} +.header { + grid-area: 1 / 1 / 2 / 6; +} +.empty-content-left { + grid-area: 2 / 1 / 6 / 2; +} +.empty-content-right { + grid-area: 2 / 5 / 6 / 6; +} +.top { + grid-area: 2 / 2 / 3 / 5; + + @include media("<tablet") { + grid-area: 2 / 1 / 3 / 6; + padding-inline: 2em; + } +} +.left { + grid-area: 3 / 2 / 6 / 4; + + @include media("<tablet") { + grid-area: 3 / 1 / 6 / 6; + padding-inline: 2em; + } +} +.right { + grid-area: 3 / 4 / 6 / 5; +} +</style> diff --git a/frontend/layouts/InternalPage.vue b/frontend/layouts/InternalPage.vue deleted file mode 100644 index 408073de2a..0000000000 --- a/frontend/layouts/InternalPage.vue +++ /dev/null @@ -1,35 +0,0 @@ -<template> - <main class="internal-page"> - <div class="internal-page__header"> - <slot name="header">here is the header</slot> - </div> - <main class="internal-page__container"> - <slot name="page-header">here is the page header</slot> - <slot name="page-content">here is the page content</slot> - </main> - </main> -</template> - -<script> -export default { - name: "InternalPage", -}; -</script> - -<style lang="scss" scoped> -.internal-page { - background: palette(white); - &__container { - display: flex; - flex-direction: column; - height: calc(100vh - $topbarHeight); - overflow: auto; - max-width: 1500px; - padding: 0 $base-space * 8; - margin: 0 auto; - @include media("<desktop") { - padding: 0 $base-space * 2; - } - } -} -</style> diff --git a/frontend/package.json b/frontend/package.json index 6da183b7c0..517c9e9102 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "argilla", - "version": "1.29.0-dev", + "version": "1.28.0", "private": true, "scripts": { "dev": "nuxt", diff --git a/frontend/pages/dataset/_id/annotation-mode/useAnnotationModeViewModel.ts b/frontend/pages/dataset/_id/annotation-mode/useAnnotationModeViewModel.ts index f82ebb78ec..1882ea2962 100644 --- a/frontend/pages/dataset/_id/annotation-mode/useAnnotationModeViewModel.ts +++ b/frontend/pages/dataset/_id/annotation-mode/useAnnotationModeViewModel.ts @@ -62,7 +62,7 @@ export const useAnnotationModeViewModel = () => { }, { key: "search", - value: recordCriteria.value.committed.searchText.urlParams, + value: recordCriteria.value.committed.searchText, }, { key: "metadata", diff --git a/frontend/pages/dataset/_id/settings.vue b/frontend/pages/dataset/_id/settings.vue index ed063a2703..3a5471f82a 100644 --- a/frontend/pages/dataset/_id/settings.vue +++ b/frontend/pages/dataset/_id/settings.vue @@ -1,49 +1,50 @@ <template> <BaseLoading v-if="isLoadingDataset" /> - <InternalPage v-else> + <HeaderAndOneColumn v-else> <template v-slot:header> <HeaderFeedbackTaskComponent :datasetId="datasetId" :breadcrumbs="breadcrumbs" /> </template> - <template v-slot:page-header> - <TopDatasetSettingsFeedbackTaskContent - :separator="!isAdminOrOwnerRole" - @goToDataset="goToDataset" - /> - </template> - <template v-slot:page-content> - <SettingsInfoReadOnly - v-if="!isAdminOrOwnerRole" - :settings="datasetSetting" - /> - <BaseTabsAndContent - v-else - :tabs="tabs" - tab-size="large" - class="settings__tabs-content" - > - <template v-slot="{ currentComponent }"> - <component - :is="currentComponent" - :key="currentComponent" - :settings="datasetSetting" - /> - </template> - </BaseTabsAndContent> + <template v-slot:center> + <div class="settings__wrapper"> + <TopDatasetSettingsFeedbackTaskContent + class="settings__header" + :separator="!isAdminOrOwnerRole" + @goToDataset="goToDataset" + /> + <SettingsInfoReadOnly + v-if="!isAdminOrOwnerRole" + :settings="datasetSetting" + /> + <BaseTabsAndContent + v-else + :tabs="tabs" + tab-size="large" + class="settings__tabs-content" + > + <template v-slot="{ currentComponent }"> + <component + :is="currentComponent" + :key="currentComponent" + :settings="datasetSetting" + /> + </template> + </BaseTabsAndContent> + </div> </template> - </InternalPage> + </HeaderAndOneColumn> </template> <script> -import InternalPage from "@/layouts/InternalPage"; +import HeaderAndOneColumn from "@/layouts/HeaderAndOneColumn"; import { useDatasetSettingViewModel } from "./useDatasetSettingViewModel"; export default { name: "SettingPage", components: { - InternalPage, + HeaderAndOneColumn, }, setup() { return useDatasetSettingViewModel(); @@ -53,6 +54,11 @@ export default { <styles lang="scss" scoped> .settings { + &__wrapper { + display: flex; + flex-direction: column; + height: 100%; + } &__tabs { &-content { display: flex; diff --git a/frontend/pages/datasets/_workspace/_dataset/settings.vue b/frontend/pages/datasets/_workspace/_dataset/settings.vue index 80be14d112..7d03a7da80 100644 --- a/frontend/pages/datasets/_workspace/_dataset/settings.vue +++ b/frontend/pages/datasets/_workspace/_dataset/settings.vue @@ -1,26 +1,24 @@ <template> - <InternalPage> + <HeaderAndTopAndTwoColumns> <template v-slot:header> <HeaderComponent /> </template> - <template v-slot:page-header> + <template v-slot:top> <TopDatasetSettingsContent /> </template> - <template v-slot:page-content> - <div> - <LeftDatasetSettingsContent /> - </div> + <template v-slot:left> + <LeftDatasetSettingsContent /> </template> - </InternalPage> + </HeaderAndTopAndTwoColumns> </template> <script> -import InternalPage from "@/layouts/InternalPage"; +import HeaderAndTopAndTwoColumns from "@/layouts/HeaderAndTopAndTwoColumns"; export default { name: "SettingsPage", components: { - InternalPage, + HeaderAndTopAndTwoColumns, }, }; </script> diff --git a/frontend/pages/user-settings.vue b/frontend/pages/user-settings.vue index 3822c7c7d7..f0cb665d45 100644 --- a/frontend/pages/user-settings.vue +++ b/frontend/pages/user-settings.vue @@ -1,5 +1,5 @@ <template> - <InternalPage> + <HeaderAndTopAndTwoColumns> <template v-slot:header> <HeaderFeedbackTaskComponent :breadcrumbs="[ @@ -8,22 +8,22 @@ ]" /> </template> - <template v-slot:page-header> - <UserSettingsHeader /> + <template v-slot:top> + <TopUserSettingsContent /> </template> - <template v-slot:page-content> - <UserSettingsContent /> + <template v-slot:left> + <LeftUserSettingsContent /> </template> - </InternalPage> + </HeaderAndTopAndTwoColumns> </template> <script> -import InternalPage from "@/layouts/InternalPage"; +import HeaderAndTopAndTwoColumns from "@/layouts/HeaderAndTopAndTwoColumns"; export default { name: "UserSettingsPage", components: { - InternalPage, + HeaderAndTopAndTwoColumns, }, }; </script> diff --git a/frontend/translation/de.js b/frontend/translation/de.js index b32fb08cb9..cd45f7d808 100644 --- a/frontend/translation/de.js +++ b/frontend/translation/de.js @@ -7,7 +7,6 @@ export default { minimize: "Minimieren", select: "Auswählen", search: "Suchen", - searchPlaceholder: "Eingabe einer Abfrage", searchDatasets: "Durchsuche Datensätze", expand: "Erweitern", copied: "Kopiert", @@ -15,7 +14,6 @@ export default { copyLink: "Link kopieren", refresh: "Refresh", typeYourText: "Type your text", - all: "Alle", sidebar: { progressTooltip: "Fortschritt", refreshTooltip: "Aktualisieren", diff --git a/frontend/translation/en.js b/frontend/translation/en.js index 478d3c1bc6..f4cf77cedc 100644 --- a/frontend/translation/en.js +++ b/frontend/translation/en.js @@ -7,7 +7,6 @@ export default { minimize: "Minimize", select: "Select", search: "Search", - searchPlaceholder: "Introduce a query", searchDatasets: "Search datasets", expand: "Expand", copied: "Copied", @@ -15,7 +14,6 @@ export default { copyLink: "Copy link", refresh: "Refresh", typeYourText: "Type your text", - all: "All", sidebar: { progressTooltip: "Progress", refreshTooltip: "Refresh", @@ -24,9 +22,8 @@ export default { title: "Title", description: "Description", labels: "Labels", - order: "Order", useMarkdown: "Use Markdown", - suggestionFirst: "Show suggestions first", + suggestionFirst: "Suggestion first", visibleForAnnotators: "Visible for annotators", allowExtraMetadata: "Allow extra metadata", extraMetadata: "Extra metadata", diff --git a/frontend/v1/di/di.ts b/frontend/v1/di/di.ts index b0d45cff1f..f08f1d534d 100644 --- a/frontend/v1/di/di.ts +++ b/frontend/v1/di/di.ts @@ -29,7 +29,6 @@ import { GetDatasetProgressUseCase } from "@/v1/domain/usecases/get-dataset-prog import { DeleteDatasetUseCase } from "@/v1/domain/usecases/delete-dataset-use-case"; import { GetRecordsByCriteriaUseCase } from "@/v1/domain/usecases/get-records-by-criteria-use-case"; import { LoadRecordsToAnnotateUseCase } from "@/v1/domain/usecases/load-records-to-annotate-use-case"; -import { GetFieldsUseCase } from "@/v1/domain/usecases/get-fields-use-case"; import { SubmitRecordUseCase } from "@/v1/domain/usecases/submit-record-use-case"; import { SaveDraftUseCase } from "@/v1/domain/usecases/save-draft-use-case"; import { BulkAnnotationUseCase } from "@/v1/domain/usecases/bulk-annotation-use-case"; @@ -94,8 +93,6 @@ export const loadDependencyContainer = (context: Context) => { .withDependencies(GetRecordsByCriteriaUseCase, useRecords) .build(), - register(GetFieldsUseCase).withDependency(FieldRepository).build(), - register(DiscardRecordUseCase) .withDependencies(RecordRepository, useEventDispatcher) .build(), diff --git a/frontend/v1/domain/entities/question/Question.ts b/frontend/v1/domain/entities/question/Question.ts index 3d271fbe9a..998085a9b1 100644 --- a/frontend/v1/domain/entities/question/Question.ts +++ b/frontend/v1/domain/entities/question/Question.ts @@ -140,23 +140,12 @@ export class Question { this.answer.clear(); } - reloadAnswerFromOptions() { - const valuesAnswered = this.answer.valuesAnswered; - - this.initializeAnswers(); - - if (valuesAnswered) { - this.answer.response({ value: valuesAnswered }); - } - } - restore() { this.title = this.original.title; this.description = this.original.description; this.restoreOriginal(); - - this.reloadAnswerFromOptions(); + this.initializeAnswers(); } update() { @@ -180,6 +169,10 @@ export class Question { this.suggestion = suggestion; } + reloadAnswerFromOptions() { + this.initializeAnswers(); + } + private createEmptyAnswers(): QuestionAnswer { if (this.isTextType) { return new TextQuestionAnswer(this.type, ""); diff --git a/frontend/v1/domain/entities/question/QuestionAnswer.ts b/frontend/v1/domain/entities/question/QuestionAnswer.ts index c3fa86b2bc..5faa3be8cd 100644 --- a/frontend/v1/domain/entities/question/QuestionAnswer.ts +++ b/frontend/v1/domain/entities/question/QuestionAnswer.ts @@ -60,7 +60,7 @@ type Option = { export class SpanQuestionAnswer extends QuestionAnswer { public readonly options: Option[] = []; - public values: SpanAnswer[] = []; + private values: SpanAnswer[] = []; constructor( public readonly type: QuestionType, diff --git a/frontend/v1/domain/entities/record/RecordCriteria.test.ts b/frontend/v1/domain/entities/record/RecordCriteria.test.ts index fd092c25b6..348d9f0979 100644 --- a/frontend/v1/domain/entities/record/RecordCriteria.test.ts +++ b/frontend/v1/domain/entities/record/RecordCriteria.test.ts @@ -421,9 +421,7 @@ describe("RecordCriteria", () => { "" ); - criteria.searchText.complete( - "Can ML help to improve your business processes?" - ); + criteria.searchText = "Can ML help to improve your business processes?"; expect(criteria.hasChanges).toBe(true); }); @@ -505,7 +503,7 @@ describe("RecordCriteria", () => { criteria.page.goTo(2); criteria.status = "submitted"; - criteria.searchText.complete("Love ML"); + criteria.searchText = "Love ML"; criteria.metadata.value = [ { name: "metadata1", value: ["value1"] }, { name: "metadata2", value: ["value2"] }, @@ -541,7 +539,7 @@ describe("RecordCriteria", () => { criteria.page.goTo(1); criteria.status = "discarded"; - criteria.searchText.complete("Do you love AI?"); + criteria.searchText = "Do you love AI?"; criteria.metadata.complete("your_feel.sad"); criteria.sortBy.complete("record.inserted_at.asc"); criteria.similaritySearch.order = "least"; @@ -831,9 +829,7 @@ describe("RecordCriteria", () => { criteria.reset(); - expect(criteria.searchText).toEqual({ - value: { field: "all", text: "Can AI help us?" }, - }); + expect(criteria.searchText).toEqual("Can AI help us?"); }); }); }); diff --git a/frontend/v1/domain/entities/record/RecordCriteria.ts b/frontend/v1/domain/entities/record/RecordCriteria.ts index 13242ac9be..6741233767 100644 --- a/frontend/v1/domain/entities/record/RecordCriteria.ts +++ b/frontend/v1/domain/entities/record/RecordCriteria.ts @@ -4,13 +4,12 @@ import { MetadataCriteria } from "../metadata/MetadataCriteria"; import { ResponseCriteria } from "../response/ResponseCriteria"; import { SuggestionCriteria } from "../suggestion/SuggestionCriteria"; import { PageCriteria } from "../page/PageCriteria"; -import { SearchTextCriteria } from "../search/SearchTextCriteria"; import { RecordStatus } from "./RecordAnswer"; interface IRecordCriteria { readonly page: PageCriteria; readonly status: RecordStatus; - readonly searchText: SearchTextCriteria; + readonly searchText: string; readonly metadata: MetadataCriteria; readonly sortBy: SortCriteria; readonly response: ResponseCriteria; @@ -21,7 +20,7 @@ interface IRecordCriteria { class CommittedRecordCriteria implements IRecordCriteria { public readonly page: PageCriteria; public readonly status: RecordStatus; - public readonly searchText: SearchTextCriteria; + public readonly searchText: string; public readonly metadata: MetadataCriteria; public readonly sortBy: SortCriteria; public readonly response: ResponseCriteria; @@ -30,7 +29,6 @@ class CommittedRecordCriteria implements IRecordCriteria { constructor(recordCriteria: IRecordCriteria) { const pageCommitted = new PageCriteria(); - const searchTextCommitted = new SearchTextCriteria(); const similaritySearchCommitted = new SimilarityCriteria(); const metadataCommitted = new MetadataCriteria(); const sortByCommitted = new SortCriteria(); @@ -38,7 +36,6 @@ class CommittedRecordCriteria implements IRecordCriteria { const suggestionCommitted = new SuggestionCriteria(); pageCommitted.withValue(recordCriteria.page); - searchTextCommitted.withValue(recordCriteria.searchText); metadataCommitted.withValue(recordCriteria.metadata); sortByCommitted.withValue(recordCriteria.sortBy); suggestionCommitted.withValue(recordCriteria.suggestion); @@ -46,7 +43,7 @@ class CommittedRecordCriteria implements IRecordCriteria { similaritySearchCommitted.withValue(recordCriteria.similaritySearch); this.status = recordCriteria.status; - this.searchText = searchTextCommitted; + this.searchText = recordCriteria.searchText; this.page = pageCommitted; this.metadata = metadataCommitted; this.sortBy = sortByCommitted; @@ -66,7 +63,6 @@ export class RecordCriteria implements IRecordCriteria { public previous?: CommittedRecordCriteria; public page: PageCriteria; - public searchText: SearchTextCriteria; public metadata: MetadataCriteria; public sortBy: SortCriteria; public response: ResponseCriteria; @@ -77,7 +73,7 @@ export class RecordCriteria implements IRecordCriteria { public readonly datasetId: string, page: string, public status: RecordStatus, - searchText: string, + public searchText: string, metadata: string, sortBy: string, response: string, @@ -85,7 +81,6 @@ export class RecordCriteria implements IRecordCriteria { similaritySearch: string ) { this.page = new PageCriteria(); - this.searchText = new SearchTextCriteria(); this.metadata = new MetadataCriteria(); this.sortBy = new SortCriteria(); this.response = new ResponseCriteria(); @@ -107,7 +102,7 @@ export class RecordCriteria implements IRecordCriteria { } get isFilteringByText() { - return this.searchText.isCompleted; + return this.searchText.length > 0; } get isFilteringBySimilarity() { @@ -142,7 +137,7 @@ export class RecordCriteria implements IRecordCriteria { } get isFilteredByText() { - return this.committed.searchText.isCompleted; + return this.committed.searchText.length > 0; } get isFilteredByMetadata() { @@ -197,9 +192,9 @@ export class RecordCriteria implements IRecordCriteria { this.isChangingAutomatically = true; this.status = status ?? "pending"; + this.searchText = searchText ?? ""; this.page.complete(page); - this.searchText.complete(searchText); this.metadata.complete(metadata); this.sortBy.complete(sortBy); this.response.complete(response); @@ -223,9 +218,9 @@ export class RecordCriteria implements IRecordCriteria { rollback() { this.status = this.committed.status; + this.searchText = this.committed.searchText; this.page.withValue(this.committed.page); - this.searchText.withValue(this.committed.searchText); this.metadata.withValue(this.committed.metadata); this.sortBy.withValue(this.committed.sortBy); this.response.withValue(this.committed.response); @@ -249,7 +244,7 @@ export class RecordCriteria implements IRecordCriteria { this.datasetId, this.page.urlParams, this.status, - this.searchText.urlParams, + this.searchText, this.metadata.urlParams, this.sortBy.urlParams, this.response.urlParams, @@ -277,10 +272,9 @@ export class RecordCriteria implements IRecordCriteria { if (!actual) return false; if (actual.status !== previous.status) return true; + if (actual.searchText !== previous.searchText) return true; - if (!previous.searchText.isEqual(actual.searchText)) return true; if (!previous.page.isEqual(actual.page)) return true; - if (!previous.searchText.isEqual(actual.searchText)) return true; if (!previous.metadata.isEqual(actual.metadata)) return true; if (!previous.sortBy.isEqual(actual.sortBy)) return true; if (!previous.response.isEqual(actual.response)) return true; diff --git a/frontend/v1/domain/entities/search/SearchTextCriteria.test.ts b/frontend/v1/domain/entities/search/SearchTextCriteria.test.ts deleted file mode 100644 index d2d1168add..0000000000 --- a/frontend/v1/domain/entities/search/SearchTextCriteria.test.ts +++ /dev/null @@ -1,203 +0,0 @@ -import { SearchTextCriteria } from "./SearchTextCriteria"; - -describe("SearchTextCriteria", () => { - describe("complete", () => { - test("should set value to empty strings when urlParams is empty", () => { - const searchTextCriteria = new SearchTextCriteria(); - - searchTextCriteria.complete(""); - - expect(searchTextCriteria.value).toEqual({ - text: "", - field: "all", - }); - }); - - test("should set value to text and field when urlParams is not empty", () => { - const searchTextCriteria = new SearchTextCriteria(); - - searchTextCriteria.complete("text~field"); - - expect(searchTextCriteria.value).toEqual({ - text: "text", - field: "field", - }); - }); - - test("should set value to text when field is empty", () => { - const searchTextCriteria = new SearchTextCriteria(); - - searchTextCriteria.complete("text"); - - expect(searchTextCriteria.value).toEqual({ - text: "text", - field: "all", - }); - }); - - test("should set value correctly if has the separator as a text", () => { - const searchTextCriteria = new SearchTextCriteria(); - - searchTextCriteria.complete("text~two~three~all"); - - expect(searchTextCriteria.value).toEqual({ - text: "text~two~three", - field: "all", - }); - }); - - test("should set value correctly if has many separators", () => { - const searchTextCriteria = new SearchTextCriteria(); - - searchTextCriteria.complete("text~~~field"); - - expect(searchTextCriteria.value).toEqual({ - text: "text~~", - field: "field", - }); - }); - - test("should set value correctly with spaces", () => { - const searchTextCriteria = new SearchTextCriteria(); - - searchTextCriteria.complete("__text_with_spaces__~field"); - - expect(searchTextCriteria.value).toEqual({ - text: "__text with spaces__", - field: "field", - }); - }); - }); - - describe("withValue", () => { - test("should set value to empty strings when searchTextCriteria value is empty", () => { - const searchTextCriteria = new SearchTextCriteria(); - - searchTextCriteria.value = { - text: "", - field: "", - }; - - expect(searchTextCriteria.value).toEqual({ - text: "", - field: "", - }); - }); - - test("should set value to text and field when searchTextCriteria value is not empty", () => { - const searchTextCriteria = new SearchTextCriteria(); - const searchTextCriteriaToCopy = new SearchTextCriteria(); - - searchTextCriteriaToCopy.value = { - text: "text", - field: "field", - }; - - searchTextCriteria.withValue(searchTextCriteriaToCopy); - - expect(searchTextCriteria.value).toEqual({ - text: "text", - field: "field", - }); - }); - }); - - describe("reset", () => { - test("should set value to empty strings", () => { - const searchTextCriteria = new SearchTextCriteria(); - - searchTextCriteria.value = { - text: "text", - field: "field", - }; - - searchTextCriteria.reset(); - - expect(searchTextCriteria.value).toEqual({ - text: "", - field: "all", - }); - }); - }); - - describe("isCompleted", () => { - test("should return false when text is empty", () => { - const searchTextCriteria = new SearchTextCriteria(); - - searchTextCriteria.value = { - text: "", - field: "field", - }; - - expect(searchTextCriteria.isCompleted).toBe(false); - }); - - test("should return true when text is not empty", () => { - const searchTextCriteria = new SearchTextCriteria(); - - searchTextCriteria.value = { - text: "text", - field: "field", - }; - - expect(searchTextCriteria.isCompleted).toBe(true); - }); - }); - - describe("urlParams", () => { - test("should return empty string when isCompleted is false", () => { - const searchTextCriteria = new SearchTextCriteria(); - - searchTextCriteria.value = { - text: "", - field: "field", - }; - - expect(searchTextCriteria.urlParams).toBe(""); - }); - - test("should return text when field is empty", () => { - const searchTextCriteria = new SearchTextCriteria(); - - searchTextCriteria.value = { - text: "text", - field: "", - }; - - expect(searchTextCriteria.urlParams).toBe("text~all"); - }); - - test("should return text and field", () => { - const searchTextCriteria = new SearchTextCriteria(); - - searchTextCriteria.value = { - text: "text", - field: "field", - }; - - expect(searchTextCriteria.urlParams).toBe("text~field"); - }); - - test("should return text and field correctly if the text has the same separator", () => { - const searchTextCriteria = new SearchTextCriteria(); - - searchTextCriteria.value = { - text: "one~two", - field: "field", - }; - - expect(searchTextCriteria.urlParams).toBe("one~two~field"); - }); - - test("should return the url params replacing the spaces to underscores", () => { - const searchTextCriteria = new SearchTextCriteria(); - - searchTextCriteria.value = { - text: "__text with spaces__", - field: "field", - }; - - expect(searchTextCriteria.urlParams).toBe("__text_with_spaces__~field"); - }); - }); -}); diff --git a/frontend/v1/domain/entities/search/SearchTextCriteria.ts b/frontend/v1/domain/entities/search/SearchTextCriteria.ts deleted file mode 100644 index 20f230cdd5..0000000000 --- a/frontend/v1/domain/entities/search/SearchTextCriteria.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { Criteria } from "../common/Criteria"; - -interface SearchText { - text: string; - field: string; -} - -export class SearchTextCriteria extends Criteria { - public value: SearchText; - - constructor() { - super(); - - this.reset(); - } - - complete(urlParams: string) { - if (!urlParams) return; - - const splitted = urlParams.split("~"); - - if (splitted.length > 2) { - const [field, ...text] = splitted.reverse(); - - return this.setValue(text.reverse().join("~"), field); - } - - const [text, field] = splitted; - - this.setValue( - text - .split("") - .map((char, i) => - this.itWasConvertedToUnderscore(text, char, i) ? " " : char - ) - .join(""), - field - ); - } - - withValue(searchTextCriteria: SearchTextCriteria) { - this.setValue( - searchTextCriteria.value.text, - searchTextCriteria.value.field - ); - } - - reset() { - this.setValue("", "all"); - } - - get isCompleted(): boolean { - return this.value.text.length > 0; - } - - get urlParams(): string { - if (!this.isCompleted) return ""; - - if (!this.value.field?.length) { - this.value.field = "all"; - } - - return `${this.value.text.replaceAll(" ", "_")}~${this.value.field}`; - } - - get isFilteringByField() { - return this.value.field !== "all"; - } - - private setValue(text: string, field: string) { - this.value = { - text: text ?? "", - field: field ?? "all", - }; - } - - private itWasConvertedToUnderscore(text: string, char: string, i: number) { - return ( - char === "_" && - !!text[i + 1] && - text[i + 1] !== "_" && - !!text[i - 1] && - text[i - 1] !== "_" - ); - } -} diff --git a/frontend/v1/domain/usecases/dataset-setting/get-dataset-settings-use-case.ts b/frontend/v1/domain/usecases/dataset-setting/get-dataset-settings-use-case.ts index b3e0c6361f..6368d264e9 100644 --- a/frontend/v1/domain/usecases/dataset-setting/get-dataset-settings-use-case.ts +++ b/frontend/v1/domain/usecases/dataset-setting/get-dataset-settings-use-case.ts @@ -2,7 +2,6 @@ import { DatasetSetting } from "../../entities/dataset/DatasetSetting"; import { Field } from "../../entities/field/Field"; import { Metadata } from "../../entities/metadata/Metadata"; import { Question } from "../../entities/question/Question"; -import { Suggestion } from "../../entities/question/Suggestion"; import { Vector } from "../../entities/vector/Vector"; import { IDatasetRepository } from "../../services/IDatasetRepository"; import { IDatasetSettingStorage } from "../../services/IDatasetSettingStorage"; @@ -77,13 +76,10 @@ export class GetDatasetSettingsUseCase { datasetId, question.title, question.required, - question.settings ); }); - this.setUpFakeSuggestion(questions); - const fields = backendFields.map((field) => { return new Field( field.id, @@ -125,23 +121,4 @@ export class GetDatasetSettingsUseCase { metadataProperties ); } - - private setUpFakeSuggestion(questions: Question[]) { - for (const question of questions) { - if (!question.isMultiLabelType) continue; - - if (question.settings.options.length > 3) { - const suggestion = new Suggestion( - question.id, - question.id, - question.type, - question.settings.options.map((o) => o.value).slice(0, 2), - [0.5, 0.7], - "system" - ); - question.addSuggestion(suggestion); - question.response(suggestion); - } - } - } } diff --git a/frontend/v1/domain/usecases/get-fields-use-case.ts b/frontend/v1/domain/usecases/get-fields-use-case.ts deleted file mode 100644 index 5c39145028..0000000000 --- a/frontend/v1/domain/usecases/get-fields-use-case.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Field } from "../entities/field/Field"; -import { FieldRepository } from "~/v1/infrastructure/repositories"; - -export class GetFieldsUseCase { - constructor(private fieldRepository: FieldRepository) {} - - async execute(datasetId: string): Promise<Field[]> { - const fields = await this.fieldRepository.getFields(datasetId); - - return fields.map((field) => { - return new Field( - field.id, - field.name, - field.title, - "", - datasetId, - field.required, - field.settings - ); - }); - } -} diff --git a/frontend/v1/infrastructure/repositories/RecordRepository.ts b/frontend/v1/infrastructure/repositories/RecordRepository.ts index 233a4c0465..29fbe8f588 100644 --- a/frontend/v1/infrastructure/repositories/RecordRepository.ts +++ b/frontend/v1/infrastructure/repositories/RecordRepository.ts @@ -243,10 +243,7 @@ export class RecordRepository { if (isFilteringByText) { body.query.text = { - q: searchText.value.text, - field: searchText.isFilteringByField - ? searchText.value.field - : undefined, + q: searchText, }; } diff --git a/frontend/v1/infrastructure/types/record.ts b/frontend/v1/infrastructure/types/record.ts index ef8c10d153..5507716475 100644 --- a/frontend/v1/infrastructure/types/record.ts +++ b/frontend/v1/infrastructure/types/record.ts @@ -78,7 +78,6 @@ export interface BackendAdvanceSearchQuery { }; text?: { q: string; - field?: string; }; }; filters?: { diff --git a/pyproject.toml b/pyproject.toml index e1be7a5abe..a65fe5d1e9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,7 @@ dependencies = [ # Aligned pydantic version with server fastAPI "pydantic >= 1.10.7", # monitoring - "wrapt >= 1.14,< 1.15", + "wrapt >= 1.13,< 1.15", # weaksupervision "numpy < 1.24.0", # for progressbars @@ -47,8 +47,8 @@ dependencies = [ dynamic = ["version"] [project.optional-dependencies] -server = ["argilla-server"] -server-postgresql = ["argilla-server[postgresql]"] +server = ["argilla-server ~= 1.28.0"] +server-postgresql = ["argilla-server[postgresql] ~= 1.28.0"] listeners = ["schedule ~= 1.1.0"] integrations = [ "PyYAML >= 5.4.1,< 6.1.0", # Required by `argilla.client.feedback.config` just used in `HuggingFaceDatasetMixin` diff --git a/src/argilla/_version.py b/src/argilla/_version.py index 6aece702f7..48d9edcf2e 100644 --- a/src/argilla/_version.py +++ b/src/argilla/_version.py @@ -13,4 +13,4 @@ # limitations under the License. # coding: utf-8 -version = "1.29.0-dev" +version = "1.28.0" diff --git a/src/argilla/client/client.py b/src/argilla/client/client.py index 7ff6820407..59adc45e73 100644 --- a/src/argilla/client/client.py +++ b/src/argilla/client/client.py @@ -333,7 +333,6 @@ def delete(self, name: str, workspace: Optional[str] = None): if workspace is not None: self.set_workspace(workspace) - _LOGGER.info(f"Dataset {name} is being delete by {self._user.id}") datasets_api.delete_dataset(client=self.http_client, name=name) def log( From 5bb3672dde1a8840028009ded07a0184f884c264 Mon Sep 17 00:00:00 2001 From: Francisco Aranda <francis@argilla.io> Date: Fri, 24 May 2024 09:33:34 +0200 Subject: [PATCH 7/7] [DOCS] Fix uvicorn server setup (#4873) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit <!-- Thanks for your contribution! As part of our Community Growers initiative 🌱, we're donating Justdiggit bunds in your name to reforest sub-Saharan Africa. To claim your Community Growers certificate, please contact David Berenstein in our Slack community or fill in this form https://tally.so/r/n9XrxK once your PR has been merged. --> # Description Reading the [uvicorn integration docs](https://docs.argilla.io/en/latest/getting_started/installation/configurations/server_configuration.html#with-uvicorn) I realized it was out-of-dated. This PR fixes this. Closes #<issue_number> **Type of change** (Remember to title the PR according to the type of change) - [ ] Documentation update **How Has This Been Tested** (Please describe the tests that you ran to verify your changes.) - [ ] `sphinx-autobuild` (read [Developer Documentation](https://docs.argilla.io/en/latest/community/developer_docs.html#building-the-documentation) for more details) **Checklist** - [ ] I added relevant documentation - [ ] I followed the style guidelines of this project - [ ] I did a self-review of my code - [ ] I made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I filled out [the contributor form](https://tally.so/r/n9XrxK) (see text above) - [ ] I have added relevant notes to the `CHANGELOG.md` file (See https://keepachangelog.com/) --- .../installation/configurations/server_configuration.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/_source/getting_started/installation/configurations/server_configuration.md b/docs/_source/getting_started/installation/configurations/server_configuration.md index fa578a184e..d69eacbf03 100644 --- a/docs/_source/getting_started/installation/configurations/server_configuration.md +++ b/docs/_source/getting_started/installation/configurations/server_configuration.md @@ -36,11 +36,13 @@ NGINX and Traefik have been tested and are known to work with Argilla: Since the Argilla Server is built on FastAPI, you can launch it using `uvicorn`: ```bash -uvicorn argilla:app +uvicorn argilla_server:app --port 6900 ``` :::{note} For more details about FastAPI and uvicorn, see [here](https://fastapi.tiangolo.com/deployment/manually/#run-a-server-manually-uvicorn). + +You can also visit the uvicorn official documentation [here](https://www.uvicorn.org/#usage). ::: ## Environment variables