From f09150617ed2454f3074bcf93f53aae5ae637d40 Mon Sep 17 00:00:00 2001
From: Nate Sesti <33237525+sestinj@users.noreply.github.com>
Date: Mon, 9 Oct 2023 18:37:27 -0700
Subject: Preview (#541)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Strong typing (#533)

* refactor: :recycle: get rid of continuedev.src.continuedev structure

* refactor: :recycle: switching back to server folder

* feat: :sparkles: make config.py imports shorter

* feat: :bookmark: publish as pre-release vscode extension

* refactor: :recycle: refactor and add more completion params to ui

* build: :building_construction: download from preview S3

* fix: :bug: fix paths

* fix: :green_heart: package:pre-release

* ci: :green_heart: more time for tests

* fix: :green_heart: fix build scripts

* fix: :bug: fix import in run.py

* fix: :bookmark: update version to try again

* ci: 💚 Update package.json version [skip ci]

* refactor: :fire: don't check for old extensions version

* fix: :bug: small bug fixes

* fix: :bug: fix config.py import paths

* ci: 💚 Update package.json version [skip ci]

* ci: :green_heart: platform-specific builds test #1

* feat: :green_heart: ship with binary

* fix: :green_heart: fix copy statement to include.exe for windows

* fix: :green_heart: cd extension before packaging

* chore: :loud_sound: count tokens generated

* fix: :green_heart: remove npm_config_arch

* fix: :green_heart: publish as pre-release!

* chore: :bookmark: update version

* perf: :green_heart: hardcode distro paths

* fix: :bug: fix yaml syntax error

* chore: :bookmark: update version

* fix: :green_heart: update permissions and version

* feat: :bug: kill old server if needed

* feat: :lipstick: update marketplace icon for pre-release

* ci: 💚 Update package.json version [skip ci]

* feat: :sparkles: auto-reload for config.py

* feat: :wrench: update default config.py imports

* feat: :sparkles: codelens in config.py

* feat: :sparkles: select model param count from UI

* ci: 💚 Update package.json version [skip ci]

* feat: :sparkles: more model options, ollama error handling

* perf: :zap: don't show server loading immediately

* fix: :bug: fixing small UI details

* ci: 💚 Update package.json version [skip ci]

* feat: :rocket: headers param on LLM class

* fix: :bug: fix headers for openai.;y

* feat: :sparkles: highlight code on cmd+shift+L

* ci: 💚 Update package.json version [skip ci]

* feat: :lipstick: sticky top bar in gui.tsx

* fix: :loud_sound: websocket logging and horizontal scrollbar

* ci: 💚 Update package.json version [skip ci]

* feat: :sparkles: allow AzureOpenAI Service through GGML

* ci: 💚 Update package.json version [skip ci]

* fix: :bug: fix automigration

* ci: 💚 Update package.json version [skip ci]

* ci: :green_heart: upload binaries in ci, download apple silicon

* chore: :fire: remove notes

* fix: :green_heart: use curl to download binary

* fix: :green_heart: set permissions on apple silicon binary

* fix: :green_heart: testing

* fix: :green_heart: cleanup file

* fix: :green_heart: fix preview.yaml

* fix: :green_heart: only upload once per binary

* fix: :green_heart: install rosetta

* ci: :green_heart: download binary after tests

* ci: 💚 Update package.json version [skip ci]

* ci: :green_heart: prepare ci for merge to main

---------

Co-authored-by: GitHub Action <action@github.com>
---
 extension/react-app/src/components/ModelCard.tsx | 178 +++++++++++++++++------
 1 file changed, 132 insertions(+), 46 deletions(-)

(limited to 'extension/react-app/src/components/ModelCard.tsx')

diff --git a/extension/react-app/src/components/ModelCard.tsx b/extension/react-app/src/components/ModelCard.tsx
index d1cb3165..0ab6ac32 100644
--- a/extension/react-app/src/components/ModelCard.tsx
+++ b/extension/react-app/src/components/ModelCard.tsx
@@ -1,16 +1,16 @@
-import React, { useContext } from "react";
+import React, { useContext, useState } from "react";
 import styled from "styled-components";
 import { buttonColor, defaultBorderRadius, lightGray } from ".";
 import { useSelector } from "react-redux";
 import { RootStore } from "../redux/store";
 import { BookOpenIcon } from "@heroicons/react/24/outline";
 import HeaderButtonWithText from "./HeaderButtonWithText";
-import { MODEL_PROVIDER_TAG_COLORS } from "../util/modelData";
+import { MODEL_PROVIDER_TAG_COLORS, PackageDimension } from "../util/modelData";
+import InfoHover from "./InfoHover";
 
-const Div = styled.div<{ color: string; disabled: boolean }>`
+const Div = styled.div<{ color: string; disabled: boolean; hovered: boolean }>`
   border: 1px solid ${lightGray};
   border-radius: ${defaultBorderRadius};
-  padding: 4px 8px;
   position: relative;
   width: 100%;
   transition: all 0.5s;
@@ -20,13 +20,45 @@ const Div = styled.div<{ color: string; disabled: boolean }>`
       ? `
     opacity: 0.5;
     `
-      : `
-  &:hover {
+      : props.hovered
+      ? `
     border: 1px solid ${props.color};
     background-color: ${props.color}22;
+    cursor: pointer;`
+      : ""}
+`;
+
+const DimensionsDiv = styled.div`
+  display: flex;
+  justify-content: flex-end;
+  margin-left: auto;
+  padding: 4px;
+  /* width: fit-content; */
+
+  border-top: 1px solid ${lightGray};
+`;
+
+const DimensionOptionDiv = styled.div<{ selected: boolean }>`
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-right: 8px;
+  background-color: ${lightGray};
+  padding: 4px;
+  border-radius: ${defaultBorderRadius};
+  outline: 0.5px solid ${lightGray};
+
+  ${(props) =>
+    props.selected &&
+    `
+    background-color: ${buttonColor};
+    color: white;
+  `}
+
+  &:hover {
     cursor: pointer;
+    outline: 1px solid ${buttonColor};
   }
-  `}
 `;
 
 interface ModelCardProps {
@@ -35,8 +67,12 @@ interface ModelCardProps {
   tags?: string[];
   refUrl?: string;
   icon?: string;
-  onClick: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
+  onClick: (
+    e: React.MouseEvent<HTMLDivElement, MouseEvent>,
+    dimensionChoices?: string[]
+  ) => void;
   disabled?: boolean;
+  dimensions?: PackageDimension[];
 }
 
 function ModelCard(props: ModelCardProps) {
@@ -44,53 +80,103 @@ function ModelCard(props: ModelCardProps) {
     (state: RootStore) => state.config.vscMediaUrl
   );
 
+  const [dimensionChoices, setDimensionChoices] = useState<string[]>(
+    props.dimensions?.map((d) => Object.keys(d.options)[0]) || []
+  );
+
+  const [hovered, setHovered] = useState(false);
+
   return (
     <Div
       disabled={props.disabled || false}
       color={buttonColor}
-      onClick={props.disabled ? undefined : (e) => props.onClick(e)}
+      hovered={hovered}
     >
-      <div style={{ display: "flex", alignItems: "center" }}>
-        {vscMediaUrl && props.icon && (
-          <img
-            src={`${vscMediaUrl}/logos/${props.icon}`}
-            height="24px"
-            style={{ marginRight: "10px" }}
-          />
-        )}
-        <h3>{props.title}</h3>
-      </div>
-      {props.tags?.map((tag) => {
-        return (
-          <span
+      <div
+        onMouseEnter={() => setHovered(true)}
+        onMouseLeave={() => setHovered(false)}
+        className="px-2 py-1"
+        onClick={
+          props.disabled
+            ? undefined
+            : (e) => {
+                if ((e.target as any).closest("a")) {
+                  return;
+                }
+                props.onClick(e, dimensionChoices);
+              }
+        }
+      >
+        <div style={{ display: "flex", alignItems: "center" }}>
+          {vscMediaUrl && props.icon && (
+            <img
+              src={`${vscMediaUrl}/logos/${props.icon}`}
+              height="24px"
+              style={{ marginRight: "10px" }}
+            />
+          )}
+          <h3>{props.title}</h3>
+        </div>
+        {props.tags?.map((tag) => {
+          return (
+            <span
+              style={{
+                backgroundColor: `${MODEL_PROVIDER_TAG_COLORS[tag]}55`,
+                color: "white",
+                padding: "2px 4px",
+                borderRadius: defaultBorderRadius,
+                marginRight: "4px",
+              }}
+            >
+              {tag}
+            </span>
+          );
+        })}
+        <p>{props.description}</p>
+
+        {props.refUrl && (
+          <a
             style={{
-              backgroundColor: `${MODEL_PROVIDER_TAG_COLORS[tag]}55`,
-              color: "white",
-              padding: "2px 4px",
-              borderRadius: defaultBorderRadius,
-              marginRight: "4px",
+              position: "absolute",
+              right: "8px",
+              top: "8px",
             }}
+            href={props.refUrl}
+            target="_blank"
           >
-            {tag}
-          </span>
-        );
-      })}
-      <p>{props.description}</p>
+            <HeaderButtonWithText text="Read the docs">
+              <BookOpenIcon width="1.6em" height="1.6em" />
+            </HeaderButtonWithText>
+          </a>
+        )}
+      </div>
 
-      {props.refUrl && (
-        <a
-          style={{
-            position: "absolute",
-            right: "8px",
-            top: "8px",
-          }}
-          href={props.refUrl}
-          target="_blank"
-        >
-          <HeaderButtonWithText text="Read the docs">
-            <BookOpenIcon width="1.6em" height="1.6em" />
-          </HeaderButtonWithText>
-        </a>
+      {props.dimensions?.length && (
+        <DimensionsDiv>
+          {props.dimensions?.map((dimension, i) => {
+            return (
+              <div className="flex items-center">
+                <InfoHover msg={dimension.description} />
+                <p className="mx-2 text-sm my-0 py-0">{dimension.name}</p>
+                {Object.keys(dimension.options).map((key) => {
+                  return (
+                    <DimensionOptionDiv
+                      onClick={(e) => {
+                        e.stopPropagation();
+                        const newChoices = [...dimensionChoices];
+                        newChoices[i] = key;
+                        setDimensionChoices(newChoices);
+                      }}
+                      selected={dimensionChoices[i] === key}
+                    >
+                      {key}
+                    </DimensionOptionDiv>
+                  );
+                })}
+              </div>
+            );
+          })}
+        </DimensionsDiv>
       )}
     </Div>
   );
-- 
cgit v1.2.3-70-g09d2

