feat: tiered costs feature + admin tier management + tag selection
Build & Push Docker Image / build (push) Successful in 6m52s
Build & Push Docker Image / build (push) Successful in 6m52s
- costs: nullable notes (fix create without notes), drop renewalDate (schema + API + UI), gate POST/PATCH/DELETE to admin + costs feature - feature middleware: admin-aware hasFeature + getEntitlements union; /auth/me and login return resolved entitlements - users: tier enum (free/premium/enterprise) in create/update/list, admin UI tier select + tier badge - tags: GET /tags/all, TagInput autocomplete in new/edit tool forms, feature suggestions on focus, query invalidation on create/update - openapi: nullable ToolUpdate urls, ToolUpdate tier fields, listAllTags - Dockerfile: push-force to drop renewal_date column
This commit is contained in:
@@ -2,7 +2,7 @@ import { useLocation } from "wouter";
|
||||
import { useForm, useFieldArray } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import * as z from "zod";
|
||||
import { useCreateTool, getListToolsQueryKey, getListCategoriesQueryKey, getListAllFeaturesQueryKey, getGetTopToolsQueryKey, getGetAnalyticsSummaryQueryKey } from "@workspace/api-client-react";
|
||||
import { useCreateTool, getListToolsQueryKey, getListCategoriesQueryKey, getListAllFeaturesQueryKey, getListAllTagsQueryKey, getGetTopToolsQueryKey, getGetAnalyticsSummaryQueryKey } from "@workspace/api-client-react";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { Layout } from "@/components/layout";
|
||||
@@ -16,6 +16,7 @@ import { Wrench, Plus, X, ArrowLeft, LogIn } from "lucide-react";
|
||||
import { Link } from "wouter";
|
||||
import { CategoryCombobox } from "@/components/category-combobox";
|
||||
import { FeatureInput } from "@/components/feature-input";
|
||||
import { TagInput } from "@/components/tag-input";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
|
||||
const toolSchema = z.object({
|
||||
@@ -77,6 +78,7 @@ export default function ToolNew() {
|
||||
queryClient.invalidateQueries({ queryKey: getListToolsQueryKey() });
|
||||
queryClient.invalidateQueries({ queryKey: getListCategoriesQueryKey() });
|
||||
queryClient.invalidateQueries({ queryKey: getListAllFeaturesQueryKey() });
|
||||
queryClient.invalidateQueries({ queryKey: getListAllTagsQueryKey() });
|
||||
queryClient.invalidateQueries({ queryKey: getGetTopToolsQueryKey() });
|
||||
queryClient.invalidateQueries({ queryKey: getGetAnalyticsSummaryQueryKey() });
|
||||
setLocation(`/tools/${newTool.id}`);
|
||||
@@ -230,7 +232,7 @@ export default function ToolNew() {
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<h3 className="text-lg font-medium">Features</h3>
|
||||
<p className="text-sm text-muted-foreground">List key capabilities. Start typing to see suggestions from existing tools.</p>
|
||||
<p className="text-sm text-muted-foreground">List key capabilities. Existing features from other tools are selectable.</p>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
@@ -283,7 +285,7 @@ export default function ToolNew() {
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<h3 className="text-lg font-medium">Tags</h3>
|
||||
<p className="text-sm text-muted-foreground">Keywords to help find this tool.</p>
|
||||
<p className="text-sm text-muted-foreground">Keywords to help find this tool. Existing tags from other tools are selectable.</p>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
@@ -303,12 +305,13 @@ export default function ToolNew() {
|
||||
control={form.control}
|
||||
name={`tags.${index}.value`}
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex items-center space-y-0 relative w-[150px]">
|
||||
<FormItem className="flex items-center space-y-0 relative w-[200px]">
|
||||
<FormControl>
|
||||
<Input
|
||||
<TagInput
|
||||
placeholder="Tag"
|
||||
className="pr-8 h-9 text-sm"
|
||||
{...field}
|
||||
onChange={field.onChange}
|
||||
value={field.value ?? ""}
|
||||
data-testid={`input-tag-${index}`}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
Reference in New Issue
Block a user