diff --git a/docs/schema-table.md b/docs/schema-table.md index 0649731..4e22b98 100644 --- a/docs/schema-table.md +++ b/docs/schema-table.md @@ -36,7 +36,6 @@ Reference data for where plants live. | `id` | `int` | Yes | Primary key | | `name` | `string` | Yes | User-facing location name | | `notes` | `string` | No | Optional details | -| `is_enabled` | `bool` | Yes | Whether the location is available for new assignments | ## `CareAction` @@ -47,7 +46,6 @@ A reusable care verb, such as water, prune, fertilize, inspect, or repot. | `id` | `int` | Yes | Primary key | | `name` | `string` | Yes | User-facing action name | | `description` | `string` | No | Optional explanation | -| `is_enabled` | `bool` | Yes | Whether the action is available for use | ## `ActionResource` @@ -57,9 +55,7 @@ A resource used while performing care. | - | - | - | - | | `id` | `int` | Yes | Primary key | | `name` | `string` | Yes | Resource name | -| `category` | `string` | No | Optional grouping, such as `Fertilizer`, `Medium`, `Treatment`, `Equipment`, or `Container` | | `notes` | `string` | No | Optional details | -| `is_enabled` | `bool` | Yes | Whether the resource is available for use | ## `CareActivity` @@ -70,7 +66,6 @@ A configurable care activity made from one or more care actions. | `id` | `int` | Yes | Primary key | | `name` | `string` | Yes | User-facing activity name | | `notes` | `string` | No | Optional details | -| `is_enabled` | `bool` | Yes | Whether the activity is available for schedules and logs | ## `CareActivityAction` @@ -114,7 +109,6 @@ A per-plant recurring schedule for one care activity. Scheduler is the UI owner | `ends_mode` | `string` | Yes | `on` or `after` | | `ends_on` | `date` | No | End date when `ends_mode` is `on` | | `ends_after_occurrences` | `int` | No | Occurrence limit when `ends_mode` is `after` | -| `is_enabled` | `bool` | Yes | Whether this schedule contributes to care tasks | ## `ActionLog` @@ -150,7 +144,6 @@ A reusable plant flag. | `id` | `int` | Yes | Primary key | | `name` | `string` | Yes | Flag name | | `color` | `string` | Yes | Display color | -| `is_enabled` | `bool` | Yes | Whether the flag can be assigned | ## `PlantFlag` diff --git a/plant-manager-web/src/App.tsx b/plant-manager-web/src/App.tsx index a24c2a8..07d9d76 100644 --- a/plant-manager-web/src/App.tsx +++ b/plant-manager-web/src/App.tsx @@ -167,6 +167,76 @@ export function App() { } } + async function loadLocations() { + const locationsResponse = await getPlantLocations(); + + setError(null); + setPlantLocations(locationsResponse); + } + + async function loadPlants() { + const plantsResponse = await getPlants(); + + setError(null); + setPlants(plantsResponse); + } + + async function loadPlantsAndCareTasks() { + const [plantsResponse, tasksResponse] = await Promise.all([ + getPlants(), + getCareTasks(), + ]); + + setError(null); + setPlants(plantsResponse); + setCareTasks(tasksResponse); + } + + async function loadTaxaAndPlants() { + const [plantsResponse, taxaResponse] = await Promise.all([ + getPlants(), + getPlantTaxa(), + ]); + + setError(null); + setPlants(plantsResponse); + setPlantTaxa(taxaResponse); + } + + async function loadFlagsAndPlants() { + const [plantsResponse, flagsResponse] = await Promise.all([ + getPlants(), + getPlantFlags(), + ]); + + setError(null); + setPlants(plantsResponse); + setPlantFlagDefinitions(flagsResponse); + } + + async function loadCareModel() { + const [ + plantsResponse, + tasksResponse, + actionsResponse, + resourcesResponse, + activitiesResponse, + ] = await Promise.all([ + getPlants(), + getCareTasks(), + getCareActions(), + getActionResources(), + getCareActivities(), + ]); + + setError(null); + setPlants(plantsResponse); + setCareTasks(tasksResponse); + setCareActions(actionsResponse); + setActionResources(resourcesResponse); + setCareActivities(activitiesResponse); + } + useEffect(() => { queueMicrotask(() => { void loadDashboard(); @@ -201,15 +271,15 @@ export function App() { setTaxonForm((current) => ({ ...current, [field]: value })); } - function updateLocationForm(field: keyof LocationFormState, value: string | boolean) { + function updateLocationForm(field: keyof LocationFormState, value: string) { setLocationForm((current) => ({ ...current, [field]: value })); } - function updateActionForm(field: keyof ActionFormState, value: string | boolean) { + function updateActionForm(field: keyof ActionFormState, value: string) { setActionForm((current) => ({ ...current, [field]: value })); } - function updateResourceForm(field: keyof ResourceFormState, value: string | boolean) { + function updateResourceForm(field: keyof ResourceFormState, value: string) { setResourceForm((current) => ({ ...current, [field]: value })); } @@ -217,7 +287,7 @@ export function App() { setActivityForm((current) => ({ ...current, [field]: value })); } - function updateFlagDefinitionForm(field: keyof FlagDefinitionFormState, value: string | boolean) { + function updateFlagDefinitionForm(field: keyof FlagDefinitionFormState, value: string) { setFlagDefinitionForm((current) => ({ ...current, [field]: value })); } @@ -227,7 +297,7 @@ export function App() { function updateBulkScheduleForm( field: keyof BulkScheduleFormState, - value: string | boolean | string[], + value: string | string[], ) { setBulkScheduleForm((current) => ({ ...current, [field]: value })); } @@ -414,7 +484,7 @@ export function App() { await updatePlant(editingPlantId, payload); } cancelEditing(); - await loadDashboard(); + await loadPlantsAndCareTasks(); } catch { setError('Could not save the plant.'); } finally { @@ -438,7 +508,7 @@ export function App() { locationId: nextValues.locationId === undefined ? selectedPlant.locationId : nextValues.locationId, careSchedules: null, }); - await loadDashboard(); + await loadPlants(); } catch { setError('Could not update the plant assignment.'); } finally { @@ -474,7 +544,7 @@ export function App() { if (editingPlantId === plant.id) { cancelEditing(); } - await loadDashboard(); + await loadPlantsAndCareTasks(); } catch { setError('Could not delete the plant.'); } finally { @@ -497,7 +567,7 @@ export function App() { await updatePlantTaxon(editingTaxonId, payload); } cancelEditingTaxon(); - await loadDashboard(); + await loadTaxaAndPlants(); } catch { setError('Could not save the taxon.'); } finally { @@ -517,7 +587,7 @@ export function App() { if (editingTaxonId === taxon.id) { cancelEditingTaxon(); } - await loadDashboard(); + await loadTaxaAndPlants(); } catch { setError('Could not delete the taxon. It may still be used by a plant.'); } finally { @@ -540,7 +610,7 @@ export function App() { await updatePlantLocation(editingLocationId, payload); } cancelEditingLocation(); - await loadDashboard(); + await loadLocations(); } catch { setError('Could not save the location.'); } finally { @@ -549,7 +619,7 @@ export function App() { } async function removeLocation(location: PlantLocation) { - const confirmed = window.confirm(`Delete ${location.name}? Locations in use will be disabled instead.`); + const confirmed = window.confirm(`Delete ${location.name}? Locations assigned to plants cannot be deleted.`); if (!confirmed) { return; } @@ -560,10 +630,10 @@ export function App() { if (editingLocationId === location.id) { cancelEditingLocation(); } - await loadDashboard(); + await loadLocations(); } catch { - await loadDashboard(); - setError('Could not delete the location. If it is in use, it was disabled instead.'); + await loadLocations(); + setError('Could not delete the location. It may still be assigned to a plant.'); } finally { setIsSaving(false); } @@ -584,7 +654,7 @@ export function App() { await updateCareAction(editingActionId, payload); } cancelEditingAction(); - await loadDashboard(); + await loadCareModel(); } catch { setError('Could not save the action.'); } finally { @@ -593,7 +663,7 @@ export function App() { } async function removeAction(action: CareAction) { - const confirmed = window.confirm(`Delete ${action.name}? Actions with care history will be disabled instead.`); + const confirmed = window.confirm(`Delete ${action.name}? Actions with care history cannot be deleted.`); if (!confirmed) { return; } @@ -604,10 +674,10 @@ export function App() { if (editingActionId === action.id) { cancelEditingAction(); } - await loadDashboard(); + await loadCareModel(); } catch { - await loadDashboard(); - setError('Could not delete the action. If it has care history, it was disabled instead.'); + await loadCareModel(); + setError('Could not delete the action. It may still have care history.'); } finally { setIsSaving(false); } @@ -628,7 +698,7 @@ export function App() { await updateActionResource(editingResourceId, payload); } cancelEditingResource(); - await loadDashboard(); + await loadCareModel(); } catch { setError('Could not save the resource.'); } finally { @@ -648,7 +718,7 @@ export function App() { if (editingResourceId === resource.id) { cancelEditingResource(); } - await loadDashboard(); + await loadCareModel(); } catch { setError('Could not delete the resource.'); } finally { @@ -671,7 +741,7 @@ export function App() { await updateCareActivity(editingActivityId, payload); } cancelEditingActivity(); - await loadDashboard(); + await loadCareModel(); } catch { setError('Could not save the activity.'); } finally { @@ -680,7 +750,7 @@ export function App() { } async function removeActivity(activity: CareActivity) { - const confirmed = window.confirm(`Delete ${activity.name}? Activities in use will be disabled instead.`); + const confirmed = window.confirm(`Delete ${activity.name}? Activities in use cannot be deleted.`); if (!confirmed) { return; } @@ -691,10 +761,10 @@ export function App() { if (editingActivityId === activity.id) { cancelEditingActivity(); } - await loadDashboard(); + await loadCareModel(); } catch { - await loadDashboard(); - setError('Could not delete the activity. If it is in use, it was disabled instead.'); + await loadCareModel(); + setError('Could not delete the activity. It may still be in use.'); } finally { setIsSaving(false); } @@ -715,7 +785,7 @@ export function App() { await updatePlantFlag(editingFlagDefinitionId, payload); } cancelEditingFlagDefinition(); - await loadDashboard(); + await loadFlagsAndPlants(); } catch { setError('Could not save the plant flag.'); } finally { @@ -733,7 +803,7 @@ export function App() { try { await savePlantCareSchedulesBulk(toBulkSchedulePayload(bulkScheduleForm)); setBulkScheduleForm(emptyBulkScheduleForm); - await loadDashboard(); + await loadPlantsAndCareTasks(); } catch { setError('Could not apply the care schedule.'); } finally { @@ -751,7 +821,7 @@ export function App() { try { await removePlantCareSchedulesBulk(toBulkSchedulePayload(bulkScheduleForm)); setBulkScheduleForm(emptyBulkScheduleForm); - await loadDashboard(); + await loadPlantsAndCareTasks(); } catch { setError('Could not remove the care schedule.'); } finally { @@ -760,7 +830,7 @@ export function App() { } async function removeFlagDefinition(flag: PlantFlagDefinition) { - const confirmed = window.confirm(`Delete ${flag.name}? Flags assigned to plants will be disabled instead.`); + const confirmed = window.confirm(`Delete ${flag.name}? Flags assigned to plants cannot be deleted.`); if (!confirmed) { return; } @@ -771,10 +841,10 @@ export function App() { if (editingFlagDefinitionId === flag.id) { cancelEditingFlagDefinition(); } - await loadDashboard(); + await loadFlagsAndPlants(); } catch { - await loadDashboard(); - setError('Could not delete the flag. If it is assigned to plants, it was disabled instead.'); + await loadFlagsAndPlants(); + setError('Could not delete the flag. It may still be assigned to a plant.'); } finally { setIsSaving(false); } @@ -790,7 +860,7 @@ export function App() { try { await assignPlantFlag(selectedPlantId, toPlantFlagPayload(plantFlagForm)); setPlantFlagForm(emptyPlantFlagForm); - await loadDashboard(); + await loadPlants(); } catch { setError('Could not attach the plant flag.'); } finally { @@ -806,7 +876,7 @@ export function App() { setIsSaving(true); try { await resolvePlantFlag(selectedPlantId, flag.id); - await loadDashboard(); + await loadPlants(); } catch { setError('Could not resolve the plant flag.'); } finally { @@ -827,7 +897,7 @@ export function App() { setIsSaving(true); try { await removePlantFlagAssignment(selectedPlantId, flag.id); - await loadDashboard(); + await loadPlants(); } catch { setError('Could not remove the plant flag.'); } finally { @@ -845,7 +915,7 @@ export function App() { notes: '', resources: [], }); - await loadDashboard(); + await loadPlantsAndCareTasks(); } catch { setError('Could not log the care task.'); } finally { @@ -874,7 +944,7 @@ export function App() { notes: '', resources: [], }); - await loadDashboard(); + await loadPlantsAndCareTasks(); } catch { setError('Could not log the due tasks.'); } finally { @@ -985,11 +1055,11 @@ export function App() {

Catalog Status

{dueCount} due

-

{plantLocations.filter((location) => location.isEnabled).length} active locations

-

{careActivities.filter((activity) => activity.isEnabled).length} active activities

-

{careActions.filter((action) => action.isEnabled).length} active actions

-

{actionResources.filter((resource) => resource.isEnabled).length} active resources

-

{plantFlagDefinitions.filter((flag) => flag.isEnabled).length} active flags

+

{plantLocations.length} locations

+

{careActivities.length} activities

+

{careActions.length} actions

+

{actionResources.length} resources

+

{plantFlagDefinitions.length} flags

diff --git a/plant-manager-web/src/components/ActionsView.tsx b/plant-manager-web/src/components/ActionsView.tsx index c8743b4..7389883 100644 --- a/plant-manager-web/src/components/ActionsView.tsx +++ b/plant-manager-web/src/components/ActionsView.tsx @@ -15,7 +15,7 @@ type ActionsViewProps = { onCloseDetail: () => void; onDelete: (action: CareAction) => void; onEdit: (action: CareAction) => void; - onFieldChange: (field: keyof ActionFormState, value: string | boolean) => void; + onFieldChange: (field: keyof ActionFormState, value: string) => void; onNew: () => void; onOpenDetail: (action: CareAction) => void; onSave: () => void; @@ -39,15 +39,13 @@ export function ActionsView({ onOpenDetail, onSave, }: ActionsViewProps) { - const enabledCount = actions.filter((action) => action.isEnabled).length; - return ( <>

Care menu

- {isLoading ? 'Loading actions' : `${enabledCount} actions enabled`} + {isLoading ? 'Loading actions' : `${actions.length} actions`}

{error ?? 'Configure the care actions available when logging plant work.'}

@@ -78,10 +76,6 @@ export function ActionsView({ Description {selectedAction.description ?? 'No description'} -
- Status - {selectedAction.isEnabled ? 'Enabled' : 'Disabled'} -
) : null} @@ -113,14 +107,6 @@ export function ActionsView({ onChange={(event) => onFieldChange('description', event.target.value)} /> -
@@ -151,8 +137,6 @@ export function ActionsView({

{action.name}

{action.description ?? 'No description'} - {' - '} - {action.isEnabled ? 'Enabled' : 'Disabled'}

diff --git a/plant-manager-web/src/components/ActivitiesView.tsx b/plant-manager-web/src/components/ActivitiesView.tsx index 704534a..2c789e8 100644 --- a/plant-manager-web/src/components/ActivitiesView.tsx +++ b/plant-manager-web/src/components/ActivitiesView.tsx @@ -46,10 +46,6 @@ export function ActivitiesView({ onSave, resources, }: ActivitiesViewProps) { - const enabledCount = activities.filter((activity) => activity.isEnabled).length; - const enabledActions = actions.filter((action) => action.isEnabled); - const enabledResources = resources.filter((resource) => resource.isEnabled); - function updateAction(index: number, nextAction: ActivityFormState['actions'][number]) { onFieldChange( 'actions', @@ -77,7 +73,7 @@ export function ActivitiesView({

Care activities

- {isLoading ? 'Loading activities' : `${enabledCount} activities enabled`} + {isLoading ? 'Loading activities' : `${activities.length} activities`}

{error ?? 'Configure reusable care bundles with actions and per-action resources.'}

@@ -108,10 +104,6 @@ export function ActivitiesView({ Notes {selectedActivity.notes ?? 'No notes'}
-
- Status - {selectedActivity.isEnabled ? 'Enabled' : 'Disabled'} -
{selectedActivity.actions.length === 0 ? ( @@ -192,7 +184,7 @@ export function ActivitiesView({ )} > - {enabledActions + {actions .filter((action) => !selectedActionIds.has(String(action.id))) .map((action) => ( - {enabledResources + {resources .filter((resource) => !selectedResourceIds.has(String(resource.id))) .map((resource) => (
@@ -391,7 +375,7 @@ export function ActivitiesView({

{activity.name}

-

{formatActivitySummary(activity)} - {activity.isEnabled ? 'Enabled' : 'Disabled'}

+

{formatActivitySummary(activity)}

-
- Status - {selectedFlag.isEnabled ? 'Enabled' : 'Disabled'} -
) : null} @@ -118,14 +112,6 @@ export function FlagsView({ onChange={(event) => onFieldChange('color', event.target.value)} /> -
@@ -154,7 +140,6 @@ export function FlagsView({

{flag.name}

-

{flag.isEnabled ? 'Enabled' : 'Disabled'}

diff --git a/plant-manager-web/src/components/LocationsView.tsx b/plant-manager-web/src/components/LocationsView.tsx index d6b0f77..aebd105 100644 --- a/plant-manager-web/src/components/LocationsView.tsx +++ b/plant-manager-web/src/components/LocationsView.tsx @@ -15,7 +15,7 @@ type LocationsViewProps = { onCloseDetail: () => void; onDelete: (location: PlantLocation) => void; onEdit: (location: PlantLocation) => void; - onFieldChange: (field: keyof LocationFormState, value: string | boolean) => void; + onFieldChange: (field: keyof LocationFormState, value: string) => void; onNew: () => void; onOpenDetail: (location: PlantLocation) => void; onSave: () => void; @@ -39,15 +39,13 @@ export function LocationsView({ onOpenDetail, onSave, }: LocationsViewProps) { - const enabledCount = locations.filter((location) => location.isEnabled).length; - return ( <>

Location library

- {isLoading ? 'Loading locations' : `${enabledCount} locations enabled`} + {isLoading ? 'Loading locations' : `${locations.length} locations`}

{error ?? 'Create and maintain the places where plants live.'}

@@ -78,10 +76,6 @@ export function LocationsView({ Notes {selectedLocation.notes ?? 'No notes'}
-
- Status - {selectedLocation.isEnabled ? 'Enabled' : 'Disabled'} -
) : null} @@ -113,14 +107,6 @@ export function LocationsView({ onChange={(event) => onFieldChange('notes', event.target.value)} /> -
@@ -151,8 +137,6 @@ export function LocationsView({

{location.name}

{location.notes ?? 'No notes'} - {' - '} - {location.isEnabled ? 'Enabled' : 'Disabled'}

diff --git a/plant-manager-web/src/components/PlantManagementView.tsx b/plant-manager-web/src/components/PlantManagementView.tsx index 240200d..6f9ad8e 100644 --- a/plant-manager-web/src/components/PlantManagementView.tsx +++ b/plant-manager-web/src/components/PlantManagementView.tsx @@ -48,9 +48,6 @@ export function PlantManagementView({ onSetLocation, onSetTaxon, }: PlantManagementViewProps) { - const enabledFlags = plantFlagDefinitions.filter((flag) => flag.isEnabled); - const enabledLocations = plantLocations.filter((location) => - location.isEnabled || location.id === selectedPlant?.locationId); const selectedTaxon = plantTaxa.find((taxon) => taxon.id === selectedPlant?.taxonId); const selectedLocation = plantLocations.find((location) => location.id === selectedPlant?.locationId); const activeFlags = selectedPlant?.flags.filter((flag) => flag.resolvedOn === null) ?? []; @@ -148,9 +145,9 @@ export function PlantManagementView({ onChange={(event) => onSetLocation(event.target.value)} > - {enabledLocations.map((location) => ( + {plantLocations.map((location) => ( ))} @@ -162,10 +159,6 @@ export function PlantManagementView({ Location {selectedLocation.name}
-
- Status - {selectedLocation.isEnabled ? 'Enabled' : 'Disabled'} -
{selectedLocation.notes ? (
Notes @@ -202,7 +195,7 @@ export function PlantManagementView({ onChange={(event) => onFieldChange('plantFlagDefinitionId', event.target.value)} > - {enabledFlags.map((flag) => ( + {plantFlagDefinitions.map((flag) => ( diff --git a/plant-manager-web/src/components/ResourcesView.tsx b/plant-manager-web/src/components/ResourcesView.tsx index 478c1cf..81c87e9 100644 --- a/plant-manager-web/src/components/ResourcesView.tsx +++ b/plant-manager-web/src/components/ResourcesView.tsx @@ -14,7 +14,7 @@ type ResourcesViewProps = { onCloseDetail: () => void; onDelete: (resource: ActionResource) => void; onEdit: (resource: ActionResource) => void; - onFieldChange: (field: keyof ResourceFormState, value: string | boolean) => void; + onFieldChange: (field: keyof ResourceFormState, value: string) => void; onNew: () => void; onOpenDetail: (resource: ActionResource) => void; onSave: () => void; @@ -39,15 +39,13 @@ export function ResourcesView({ onSave, resources, }: ResourcesViewProps) { - const enabledCount = resources.filter((resource) => resource.isEnabled).length; - return ( <>

Resource library

- {isLoading ? 'Loading resources' : `${enabledCount} resources enabled`} + {isLoading ? 'Loading resources' : `${resources.length} resources`}

{error ?? 'Configure materials, products, tools, and containers used during care.'}

@@ -74,18 +72,10 @@ export function ResourcesView({
-
- Category - {selectedResource.category ?? 'Uncategorized'} -
Notes {selectedResource.notes ?? 'No notes'}
-
- Status - {selectedResource.isEnabled ? 'Enabled' : 'Disabled'} -
) : null} @@ -110,13 +100,6 @@ export function ResourcesView({ onChange={(event) => onFieldChange('name', event.target.value)} /> - -
@@ -161,11 +136,7 @@ export function ResourcesView({

{resource.name}

- {resource.category ?? 'Uncategorized'} - {' - '} {resource.notes ?? 'No notes'} - {' - '} - {resource.isEnabled ? 'Enabled' : 'Disabled'}

diff --git a/plant-manager-web/src/components/SchedulesView.tsx b/plant-manager-web/src/components/SchedulesView.tsx index 6b79f9d..770d2f9 100644 --- a/plant-manager-web/src/components/SchedulesView.tsx +++ b/plant-manager-web/src/components/SchedulesView.tsx @@ -10,7 +10,7 @@ type SchedulesViewProps = { isLoading: boolean; isSaving: boolean; plants: Plant[]; - onFieldChange: (field: keyof BulkScheduleFormState, value: string | boolean | string[]) => void; + onFieldChange: (field: keyof BulkScheduleFormState, value: string | string[]) => void; onRemove: () => void; onSave: () => void; }; @@ -46,7 +46,6 @@ export function SchedulesView({ onSave, }: SchedulesViewProps) { const [plantQuery, setPlantQuery] = useState(''); - const enabledActivities = activities.filter((activity) => activity.isEnabled); const visiblePlants = useMemo( () => filterPlants(plants, plantQuery), [plants, plantQuery], @@ -93,7 +92,7 @@ export function SchedulesView({ onChange={(event) => onFieldChange('careActivityId', event.target.value)} > - {enabledActivities.map((activity) => ( + {activities.map((activity) => ( @@ -109,15 +108,6 @@ export function SchedulesView({ onChange={(event) => onFieldChange('scheduledFor', event.target.value)} /> -
@@ -348,7 +338,7 @@ export function SchedulesView({
{plant.careSchedules.map((schedule) => ( - {schedule.action} / {formatRecurrence(schedule)} / {schedule.isEnabled ? schedule.nextCare : 'Disabled'} + {schedule.action} / {formatRecurrence(schedule)} / {schedule.nextCare} ))}
@@ -372,7 +362,7 @@ function formatPlantScheduleSummary(plant: Plant, selectedActivity?: CareActivit return `No ${selectedActivity.name} schedule`; } - return `${selectedActivity.name}: ${formatRecurrence(schedule)} - ${schedule.isEnabled ? schedule.nextCare : 'disabled'}`; + return `${selectedActivity.name}: ${formatRecurrence(schedule)} - ${schedule.nextCare}`; } function filterPlants(plants: Plant[], query: string) { diff --git a/plant-manager-web/src/domain.ts b/plant-manager-web/src/domain.ts index 43212cf..a270261 100644 --- a/plant-manager-web/src/domain.ts +++ b/plant-manager-web/src/domain.ts @@ -31,7 +31,6 @@ export type PlantCareSchedule = { lastPerformed: string; nextCare: string; status: CareStatus; - isEnabled: boolean; }; export type ScheduleRecurrenceMode = 'none' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'custom'; @@ -52,22 +51,18 @@ export type PlantLocation = { id: number; name: string; notes: string | null; - isEnabled: boolean; }; export type CareAction = { id: number; name: string; description: string | null; - isEnabled: boolean; }; export type ActionResource = { id: number; name: string; - category: string | null; notes: string | null; - isEnabled: boolean; }; export type CareActivity = { @@ -77,7 +72,6 @@ export type CareActivity = { action: string; actions: CareActivityAction[]; notes: string | null; - isEnabled: boolean; }; export type CareActivityAction = { @@ -91,7 +85,6 @@ export type CareActivityAction = { export type CareActivityActionResource = { actionResourceId: number; name: string; - category: string | null; quantity: number | null; unit: string | null; notes: string | null; @@ -101,7 +94,6 @@ export type PlantFlagDefinition = { id: number; name: string; color: string; - isEnabled: boolean; }; export type PlantFlag = { @@ -132,7 +124,6 @@ export type PlantCareSchedulePayload = { endsMode: ScheduleEndsMode; endsOn: string | null; endsAfterOccurrences: number | null; - isEnabled: boolean; }; export type BulkPlantCareSchedulePayload = { @@ -147,7 +138,6 @@ export type BulkPlantCareSchedulePayload = { endsMode: ScheduleEndsMode; endsOn: string | null; endsAfterOccurrences: number | null; - isEnabled: boolean; }; export type PlantTaxonPayload = { @@ -162,27 +152,22 @@ export type PlantTaxonPayload = { export type PlantLocationPayload = { name: string; notes: string | null; - isEnabled: boolean; }; export type CareActionPayload = { name: string; description: string | null; - isEnabled: boolean; }; export type ActionResourcePayload = { name: string; - category: string | null; notes: string | null; - isEnabled: boolean; }; export type CareActivityPayload = { name: string; actions: CareActivityActionPayload[]; notes: string | null; - isEnabled: boolean; }; export type CareActivityActionPayload = { @@ -200,7 +185,6 @@ export type CareActivityActionResourcePayload = { export type PlantFlagDefinitionPayload = { name: string; color: string | null; - isEnabled: boolean; }; export type AssignPlantFlagPayload = { diff --git a/plant-manager-web/src/form-state.ts b/plant-manager-web/src/form-state.ts index ae37e3d..4e33c3c 100644 --- a/plant-manager-web/src/form-state.ts +++ b/plant-manager-web/src/form-state.ts @@ -36,27 +36,22 @@ export const emptyTaxonForm = { export const emptyLocationForm = { name: '', notes: '', - isEnabled: true, }; export const emptyActionForm = { name: '', description: '', - isEnabled: true, }; export const emptyResourceForm = { name: '', - category: '', notes: '', - isEnabled: true, }; export const emptyActivityForm = { name: '', actions: [] as CareActivityActionFormState[], notes: '', - isEnabled: true, }; export type CareActivityActionResourceFormState = { @@ -74,7 +69,6 @@ export type CareActivityActionFormState = { export const emptyFlagDefinitionForm = { name: '', color: '#f2f2f2', - isEnabled: true, }; export const emptyPlantFlagForm = { @@ -94,7 +88,6 @@ export const emptyBulkScheduleForm = { endsMode: 'after', endsOn: '', endsAfterOccurrences: '12', - isEnabled: true, plantIds: [] as string[], }; @@ -128,7 +121,6 @@ export function toLocationForm(location: PlantLocation): LocationFormState { return { name: location.name, notes: location.notes ?? '', - isEnabled: location.isEnabled, }; } @@ -136,7 +128,6 @@ export function toLocationPayload(form: LocationFormState): PlantLocationPayload return { name: form.name.trim(), notes: form.notes.trim() || null, - isEnabled: form.isEnabled, }; } @@ -166,7 +157,6 @@ export function toActionForm(action: CareAction): ActionFormState { return { name: action.name, description: action.description ?? '', - isEnabled: action.isEnabled, }; } @@ -174,25 +164,20 @@ export function toActionPayload(form: ActionFormState): CareActionPayload { return { name: form.name.trim(), description: form.description.trim() || null, - isEnabled: form.isEnabled, }; } export function toResourceForm(resource: ActionResource): ResourceFormState { return { name: resource.name, - category: resource.category ?? '', notes: resource.notes ?? '', - isEnabled: resource.isEnabled, }; } export function toResourcePayload(form: ResourceFormState): ActionResourcePayload { return { name: form.name.trim(), - category: form.category.trim() || null, notes: form.notes.trim() || null, - isEnabled: form.isEnabled, }; } @@ -209,7 +194,6 @@ export function toActivityForm(activity: CareActivity): ActivityFormState { })), })), notes: activity.notes ?? '', - isEnabled: activity.isEnabled, }; } @@ -226,7 +210,6 @@ export function toActivityPayload(form: ActivityFormState): CareActivityPayload })), })), notes: form.notes.trim() || null, - isEnabled: form.isEnabled, }; } @@ -234,7 +217,6 @@ export function toFlagDefinitionForm(flag: PlantFlagDefinition): FlagDefinitionF return { name: flag.name, color: flag.color, - isEnabled: flag.isEnabled, }; } @@ -242,7 +224,6 @@ export function toFlagDefinitionPayload(form: FlagDefinitionFormState): PlantFla return { name: form.name.trim(), color: form.color.trim() || null, - isEnabled: form.isEnabled, }; } @@ -271,7 +252,6 @@ export function toBulkSchedulePayload(form: BulkScheduleFormState): BulkPlantCar : form.endsMode === 'after' ? Number(form.endsAfterOccurrences) : null, - isEnabled: form.isEnabled, }; } diff --git a/plant-manager/Contracts.cs b/plant-manager/Contracts.cs index e8e11eb..3d8a0a0 100644 --- a/plant-manager/Contracts.cs +++ b/plant-manager/Contracts.cs @@ -24,8 +24,7 @@ namespace plant_manager string? RepeatOnDays, string? EndsMode, DateOnly? EndsOn, - int? EndsAfterOccurrences, - bool IsEnabled); + int? EndsAfterOccurrences); public record BulkSavePlantCareScheduleRequest( IReadOnlyList PlantIds, @@ -38,8 +37,7 @@ namespace plant_manager string? RepeatOnDays, string? EndsMode, DateOnly? EndsOn, - int? EndsAfterOccurrences, - bool IsEnabled); + int? EndsAfterOccurrences); public record SavePlantTaxonRequest( string Name, @@ -51,25 +49,20 @@ namespace plant_manager public record SavePlantLocationRequest( string Name, - string? Notes, - bool IsEnabled); + string? Notes); public record SaveCareActionRequest( string Name, - string? Description, - bool IsEnabled); + string? Description); public record SaveActionResourceRequest( string Name, - string? Category, - string? Notes, - bool IsEnabled); + string? Notes); public record SaveCareActivityRequest( string Name, IReadOnlyList Actions, - string? Notes, - bool IsEnabled); + string? Notes); public record SaveCareActivityActionRequest( int CareActionId, @@ -84,7 +77,6 @@ namespace plant_manager public record CareActivityActionResourceDto( int ActionResourceId, string Name, - string? Category, decimal? Quantity, string? Unit, string? Notes) @@ -94,7 +86,6 @@ namespace plant_manager new( resource.ActionResourceId, resource.ActionResource.Name, - resource.ActionResource.Category, resource.Quantity, resource.Unit, resource.Notes); @@ -121,8 +112,7 @@ namespace plant_manager public record SavePlantFlagDefinitionRequest( string Name, - string? Color, - bool IsEnabled); + string? Color); public record AssignPlantFlagRequest( int PlantFlagDefinitionId, @@ -183,32 +173,28 @@ namespace plant_manager public record PlantLocationDto( int Id, string Name, - string? Notes, - bool IsEnabled) + string? Notes) { public static PlantLocationDto FromLocation(PlantLocation location) => - new(location.Id, location.Name, location.Notes, location.IsEnabled); + new(location.Id, location.Name, location.Notes); } public record CareActionDto( int Id, string Name, - string? Description, - bool IsEnabled) + string? Description) { public static CareActionDto FromCareAction(CareAction action) => - new(action.Id, action.Name, action.Description, action.IsEnabled); + new(action.Id, action.Name, action.Description); } public record ActionResourceDto( int Id, string Name, - string? Category, - string? Notes, - bool IsEnabled) + string? Notes) { public static ActionResourceDto FromActionResource(ActionResource resource) => - new(resource.Id, resource.Name, resource.Category, resource.Notes, resource.IsEnabled); + new(resource.Id, resource.Name, resource.Notes); } public record CareActivityDto( @@ -217,8 +203,7 @@ namespace plant_manager int CareActionId, string Action, IReadOnlyList Actions, - string? Notes, - bool IsEnabled) + string? Notes) { public static CareActivityDto FromCareActivity(CareActivity activity) => new( @@ -230,8 +215,7 @@ namespace plant_manager .OrderBy(action => action.SortOrder) .Select(CareActivityActionDto.FromCareActivityAction) .ToList(), - activity.Notes, - activity.IsEnabled); + activity.Notes); } public record PlantDto( @@ -257,7 +241,6 @@ namespace plant_manager today)) .ToList(); var nextCare = schedules - .Where(schedule => schedule.IsEnabled) .Select(schedule => { var source = plant.CareSchedules.First(item => item.Id == schedule.Id); @@ -312,8 +295,7 @@ namespace plant_manager DateOnly? LastPerformedOn, string LastPerformed, string NextCare, - string Status, - bool IsEnabled) + string Status) { public static PlantCareScheduleDto FromSchedule( PlantCareSchedule schedule, @@ -339,8 +321,7 @@ namespace plant_manager lastPerformedOn, PlantCareFormatter.FormatRelativeDate(lastPerformedOn, today, "Never"), PlantCareFormatter.FormatRelativeDate(nextCare, today, "Unscheduled"), - PlantCareFormatter.GetStatus(nextCare, today), - schedule.IsEnabled); + PlantCareFormatter.GetStatus(nextCare, today)); } private static int GetCompletedOccurrences(PlantCareSchedule schedule) => @@ -395,15 +376,13 @@ namespace plant_manager public record PlantFlagDefinitionDto( int Id, string Name, - string Color, - bool IsEnabled) + string Color) { public static PlantFlagDefinitionDto FromDefinition(PlantFlagDefinition definition) => new( definition.Id, definition.Name, - definition.Color, - definition.IsEnabled); + definition.Color); } public record PlantFlagDto( @@ -455,7 +434,6 @@ namespace plant_manager public record ActionLogResourceDto( int ActionResourceId, string Name, - string? Category, decimal? Quantity, string? Unit) { @@ -463,7 +441,6 @@ namespace plant_manager new( resource.ActionResourceId, resource.ActionResource.Name, - resource.ActionResource.Category, resource.Quantity, resource.Unit); } diff --git a/plant-manager/Data/ApplicationDbContext.cs b/plant-manager/Data/ApplicationDbContext.cs index 0ca99e4..ba474c2 100644 --- a/plant-manager/Data/ApplicationDbContext.cs +++ b/plant-manager/Data/ApplicationDbContext.cs @@ -57,7 +57,6 @@ namespace plant_manager.Data .ValueGeneratedOnAdd(); entity.Property(e => e.Name).HasMaxLength(120).IsRequired(); entity.Property(e => e.Notes).HasMaxLength(1000); - entity.Property(e => e.IsEnabled).IsRequired(); entity.HasIndex(e => e.Name).IsUnique(); }); @@ -68,7 +67,6 @@ namespace plant_manager.Data .ValueGeneratedOnAdd(); entity.Property(e => e.Name).HasMaxLength(80).IsRequired(); entity.Property(e => e.Description).HasMaxLength(400); - entity.Property(e => e.IsEnabled).IsRequired(); entity.HasIndex(e => e.Name).IsUnique(); }); @@ -78,9 +76,7 @@ namespace plant_manager.Data entity.Property(e => e.Id) .ValueGeneratedOnAdd(); entity.Property(e => e.Name).HasMaxLength(120).IsRequired(); - entity.Property(e => e.Category).HasMaxLength(80); entity.Property(e => e.Notes).HasMaxLength(1000); - entity.Property(e => e.IsEnabled).IsRequired(); entity.HasIndex(e => e.Name).IsUnique(); }); @@ -91,7 +87,6 @@ namespace plant_manager.Data .ValueGeneratedOnAdd(); entity.Property(e => e.Name).HasMaxLength(120).IsRequired(); entity.Property(e => e.Notes).HasMaxLength(1000); - entity.Property(e => e.IsEnabled).IsRequired(); entity.HasIndex(e => e.Name).IsUnique(); }); @@ -174,7 +169,6 @@ namespace plant_manager.Data entity.Property(e => e.EndsMode).HasMaxLength(20).IsRequired(); entity.Property(e => e.EndsOn); entity.Property(e => e.EndsAfterOccurrences); - entity.Property(e => e.IsEnabled).IsRequired(); entity.HasIndex(e => new { e.PlantId, e.CareActionId }).IsUnique(false); entity.HasIndex(e => new { e.PlantId, e.CareActivityId }).IsUnique(); entity.HasOne(e => e.Plant) @@ -198,7 +192,6 @@ namespace plant_manager.Data .ValueGeneratedOnAdd(); entity.Property(e => e.Name).HasMaxLength(120).IsRequired(); entity.Property(e => e.Color).HasMaxLength(20).IsRequired(); - entity.Property(e => e.IsEnabled).IsRequired(); entity.HasIndex(e => e.Name).IsUnique(); }); diff --git a/plant-manager/Data/DatabaseSeeder.cs b/plant-manager/Data/DatabaseSeeder.cs index 1c54a30..b616937 100644 --- a/plant-manager/Data/DatabaseSeeder.cs +++ b/plant-manager/Data/DatabaseSeeder.cs @@ -16,14 +16,14 @@ namespace plant_manager.Data private static readonly ActionResource[] StarterResources = [ - new() { Name = "Water", Category = "Consumable", Notes = "Plain watering resource." }, - new() { Name = "Potting Mix", Category = "Medium", Notes = "General purpose houseplant medium." }, - new() { Name = "Orchid Bark", Category = "Medium", Notes = "Chunky amendment for airflow and drainage." }, - new() { Name = "Perlite", Category = "Medium", Notes = "Lightweight amendment for drainage and aeration." }, - new() { Name = "Fertilizer", Category = "Fertilizer", Notes = "General plant nutrient." }, - new() { Name = "Nursery Pot", Category = "Container", Notes = "Basic plastic grow pot." }, - new() { Name = "Neem Oil", Category = "Treatment", Notes = "Common pest treatment." }, - new() { Name = "Pruners", Category = "Equipment", Notes = "Cutting tool for pruning or cleanup." } + new() { Name = "Water", Notes = "Plain watering resource." }, + new() { Name = "Potting Mix", Notes = "General purpose houseplant medium." }, + new() { Name = "Orchid Bark", Notes = "Chunky amendment for airflow and drainage." }, + new() { Name = "Perlite", Notes = "Lightweight amendment for drainage and aeration." }, + new() { Name = "Fertilizer", Notes = "General plant nutrient." }, + new() { Name = "Nursery Pot", Notes = "Basic plastic grow pot." }, + new() { Name = "Neem Oil", Notes = "Common pest treatment." }, + new() { Name = "Pruners", Notes = "Cutting tool for pruning or cleanup." } ]; private static readonly StarterCareActivity[] StarterCareActivities = @@ -117,8 +117,7 @@ namespace plant_manager.Data .Select(starterAction => new CareAction { Name = starterAction.Name, - Description = starterAction.Description, - IsEnabled = starterAction.IsEnabled + Description = starterAction.Description }) .ToList(); @@ -143,9 +142,7 @@ namespace plant_manager.Data .Select(starterResource => new ActionResource { Name = starterResource.Name, - Category = starterResource.Category, - Notes = starterResource.Notes, - IsEnabled = starterResource.IsEnabled + Notes = starterResource.Notes }) .ToList(); @@ -201,7 +198,6 @@ namespace plant_manager.Data return new CareActivity { Name = starterActivity.Name, - IsEnabled = true, Actions = actions }; }) @@ -229,8 +225,7 @@ namespace plant_manager.Data .Select(starterFlag => new PlantFlagDefinition { Name = starterFlag.Name, - Color = starterFlag.Color, - IsEnabled = starterFlag.IsEnabled + Color = starterFlag.Color }) .ToList(); @@ -347,8 +342,7 @@ namespace plant_manager.Data string.Equals(existingName, starterLocation, StringComparison.OrdinalIgnoreCase))) .Select(starterLocation => new PlantLocation { - Name = starterLocation, - IsEnabled = true + Name = starterLocation }) .ToList(); diff --git a/plant-manager/Data/Migrations/20260522001415_InitialCreate.Designer.cs b/plant-manager/Data/Migrations/20260522001415_InitialCreate.Designer.cs index 19de217..6404739 100644 --- a/plant-manager/Data/Migrations/20260522001415_InitialCreate.Designer.cs +++ b/plant-manager/Data/Migrations/20260522001415_InitialCreate.Designer.cs @@ -86,14 +86,6 @@ namespace plant_manager.Data.Migrations b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - - b.Property("Category") - .HasMaxLength(80) - .HasColumnType("TEXT"); - - b.Property("IsEnabled") - .HasColumnType("INTEGER"); - b.Property("Name") .IsRequired() .HasMaxLength(120) @@ -120,10 +112,6 @@ namespace plant_manager.Data.Migrations b.Property("Description") .HasMaxLength(400) .HasColumnType("TEXT"); - - b.Property("IsEnabled") - .HasColumnType("INTEGER"); - b.Property("Name") .IsRequired() .HasMaxLength(80) @@ -142,10 +130,6 @@ namespace plant_manager.Data.Migrations b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - - b.Property("IsEnabled") - .HasColumnType("INTEGER"); - b.Property("Name") .IsRequired() .HasMaxLength(120) @@ -265,10 +249,6 @@ namespace plant_manager.Data.Migrations b.Property("EveryDays") .HasColumnType("INTEGER"); - - b.Property("IsEnabled") - .HasColumnType("INTEGER"); - b.Property("PlantId") .HasColumnType("INTEGER"); @@ -347,10 +327,6 @@ namespace plant_manager.Data.Migrations .IsRequired() .HasMaxLength(20) .HasColumnType("TEXT"); - - b.Property("IsEnabled") - .HasColumnType("INTEGER"); - b.Property("Name") .IsRequired() .HasMaxLength(120) @@ -369,10 +345,6 @@ namespace plant_manager.Data.Migrations b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - - b.Property("IsEnabled") - .HasColumnType("INTEGER"); - b.Property("Name") .IsRequired() .HasMaxLength(120) diff --git a/plant-manager/Data/Migrations/20260522001415_InitialCreate.cs b/plant-manager/Data/Migrations/20260522001415_InitialCreate.cs index 6a1f0c8..92ba75f 100644 --- a/plant-manager/Data/Migrations/20260522001415_InitialCreate.cs +++ b/plant-manager/Data/Migrations/20260522001415_InitialCreate.cs @@ -18,9 +18,7 @@ namespace plant_manager.Data.Migrations Id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), Name = table.Column(type: "TEXT", maxLength: 120, nullable: false), - Category = table.Column(type: "TEXT", maxLength: 80, nullable: true), - Notes = table.Column(type: "TEXT", maxLength: 1000, nullable: true), - IsEnabled = table.Column(type: "INTEGER", nullable: false) + Notes = table.Column(type: "TEXT", maxLength: 1000, nullable: true) }, constraints: table => { @@ -34,8 +32,7 @@ namespace plant_manager.Data.Migrations Id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), Name = table.Column(type: "TEXT", maxLength: 80, nullable: false), - Description = table.Column(type: "TEXT", maxLength: 400, nullable: true), - IsEnabled = table.Column(type: "INTEGER", nullable: false) + Description = table.Column(type: "TEXT", maxLength: 400, nullable: true) }, constraints: table => { @@ -49,8 +46,7 @@ namespace plant_manager.Data.Migrations Id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), Name = table.Column(type: "TEXT", maxLength: 120, nullable: false), - Notes = table.Column(type: "TEXT", maxLength: 1000, nullable: true), - IsEnabled = table.Column(type: "INTEGER", nullable: false) + Notes = table.Column(type: "TEXT", maxLength: 1000, nullable: true) }, constraints: table => { @@ -64,8 +60,7 @@ namespace plant_manager.Data.Migrations Id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), Name = table.Column(type: "TEXT", maxLength: 120, nullable: false), - Color = table.Column(type: "TEXT", maxLength: 20, nullable: false), - IsEnabled = table.Column(type: "INTEGER", nullable: false) + Color = table.Column(type: "TEXT", maxLength: 20, nullable: false) }, constraints: table => { @@ -79,8 +74,7 @@ namespace plant_manager.Data.Migrations Id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), Name = table.Column(type: "TEXT", maxLength: 120, nullable: false), - Notes = table.Column(type: "TEXT", maxLength: 1000, nullable: true), - IsEnabled = table.Column(type: "INTEGER", nullable: false) + Notes = table.Column(type: "TEXT", maxLength: 1000, nullable: true) }, constraints: table => { @@ -238,8 +232,7 @@ namespace plant_manager.Data.Migrations RepeatOnDays = table.Column(type: "TEXT", maxLength: 40, nullable: true), EndsMode = table.Column(type: "TEXT", maxLength: 20, nullable: false), EndsOn = table.Column(type: "TEXT", nullable: true), - EndsAfterOccurrences = table.Column(type: "INTEGER", nullable: true), - IsEnabled = table.Column(type: "INTEGER", nullable: false) + EndsAfterOccurrences = table.Column(type: "INTEGER", nullable: true) }, constraints: table => { diff --git a/plant-manager/Data/Migrations/ApplicationDbContextModelSnapshot.cs b/plant-manager/Data/Migrations/ApplicationDbContextModelSnapshot.cs index 10fafba..cd8ddf3 100644 --- a/plant-manager/Data/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/plant-manager/Data/Migrations/ApplicationDbContextModelSnapshot.cs @@ -83,14 +83,6 @@ namespace plant_manager.Data.Migrations b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - - b.Property("Category") - .HasMaxLength(80) - .HasColumnType("TEXT"); - - b.Property("IsEnabled") - .HasColumnType("INTEGER"); - b.Property("Name") .IsRequired() .HasMaxLength(120) @@ -117,10 +109,6 @@ namespace plant_manager.Data.Migrations b.Property("Description") .HasMaxLength(400) .HasColumnType("TEXT"); - - b.Property("IsEnabled") - .HasColumnType("INTEGER"); - b.Property("Name") .IsRequired() .HasMaxLength(80) @@ -139,10 +127,6 @@ namespace plant_manager.Data.Migrations b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - - b.Property("IsEnabled") - .HasColumnType("INTEGER"); - b.Property("Name") .IsRequired() .HasMaxLength(120) @@ -262,10 +246,6 @@ namespace plant_manager.Data.Migrations b.Property("EveryDays") .HasColumnType("INTEGER"); - - b.Property("IsEnabled") - .HasColumnType("INTEGER"); - b.Property("PlantId") .HasColumnType("INTEGER"); @@ -344,10 +324,6 @@ namespace plant_manager.Data.Migrations .IsRequired() .HasMaxLength(20) .HasColumnType("TEXT"); - - b.Property("IsEnabled") - .HasColumnType("INTEGER"); - b.Property("Name") .IsRequired() .HasMaxLength(120) @@ -366,10 +342,6 @@ namespace plant_manager.Data.Migrations b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - - b.Property("IsEnabled") - .HasColumnType("INTEGER"); - b.Property("Name") .IsRequired() .HasMaxLength(120) diff --git a/plant-manager/Data/Models/ActionResource.cs b/plant-manager/Data/Models/ActionResource.cs index b85f096..e2dcc0e 100644 --- a/plant-manager/Data/Models/ActionResource.cs +++ b/plant-manager/Data/Models/ActionResource.cs @@ -5,9 +5,7 @@ namespace plant_manager.Data.Models public int Id { get; set; } public string Name { get; set; } = string.Empty; - public string? Category { get; set; } public string? Notes { get; set; } - public bool IsEnabled { get; set; } = true; public List CareActivityActionResources { get; set; } = []; public List ActionLogResources { get; set; } = []; diff --git a/plant-manager/Data/Models/CareAction.cs b/plant-manager/Data/Models/CareAction.cs index 9a96a23..67165de 100644 --- a/plant-manager/Data/Models/CareAction.cs +++ b/plant-manager/Data/Models/CareAction.cs @@ -6,7 +6,6 @@ namespace plant_manager.Data.Models public string Name { get; set; } = string.Empty; public string? Description { get; set; } - public bool IsEnabled { get; set; } = true; public List CareActivityActions { get; set; } = []; public List ActionLogs { get; set; } = []; diff --git a/plant-manager/Data/Models/CareActivity.cs b/plant-manager/Data/Models/CareActivity.cs index 413a492..8b0439c 100644 --- a/plant-manager/Data/Models/CareActivity.cs +++ b/plant-manager/Data/Models/CareActivity.cs @@ -6,7 +6,6 @@ namespace plant_manager.Data.Models public string Name { get; set; } = string.Empty; public string? Notes { get; set; } - public bool IsEnabled { get; set; } = true; public List Actions { get; set; } = []; public List ActionLogs { get; set; } = []; diff --git a/plant-manager/Data/Models/PlantCareSchedule.cs b/plant-manager/Data/Models/PlantCareSchedule.cs index 61c9161..5082d8c 100644 --- a/plant-manager/Data/Models/PlantCareSchedule.cs +++ b/plant-manager/Data/Models/PlantCareSchedule.cs @@ -15,7 +15,6 @@ namespace plant_manager.Data.Models public string EndsMode { get; set; } = "after"; public DateOnly? EndsOn { get; set; } public int? EndsAfterOccurrences { get; set; } - public bool IsEnabled { get; set; } = true; public Plant Plant { get; set; } = null!; public CareAction CareAction { get; set; } = null!; diff --git a/plant-manager/Data/Models/PlantFlagDefinition.cs b/plant-manager/Data/Models/PlantFlagDefinition.cs index afedbc6..b837e79 100644 --- a/plant-manager/Data/Models/PlantFlagDefinition.cs +++ b/plant-manager/Data/Models/PlantFlagDefinition.cs @@ -5,7 +5,6 @@ namespace plant_manager.Data.Models public int Id { get; set; } public string Name { get; set; } = string.Empty; public string Color { get; set; } = "#f2f2f2"; - public bool IsEnabled { get; set; } = true; public List PlantFlags { get; set; } = []; } diff --git a/plant-manager/Data/Models/PlantLocation.cs b/plant-manager/Data/Models/PlantLocation.cs index 8098b01..759fd85 100644 --- a/plant-manager/Data/Models/PlantLocation.cs +++ b/plant-manager/Data/Models/PlantLocation.cs @@ -6,7 +6,6 @@ namespace plant_manager.Data.Models public string Name { get; set; } = string.Empty; public string? Notes { get; set; } - public bool IsEnabled { get; set; } = true; public List Plants { get; set; } = []; } diff --git a/plant-manager/Endpoints/ActionLogEndpoints.cs b/plant-manager/Endpoints/ActionLogEndpoints.cs index 2577ab6..7588705 100644 --- a/plant-manager/Endpoints/ActionLogEndpoints.cs +++ b/plant-manager/Endpoints/ActionLogEndpoints.cs @@ -43,9 +43,9 @@ namespace plant_manager.Endpoints } var primaryAction = activity.PrimaryAction(); - if (!activity.IsEnabled || primaryAction is null || activity.Actions.Any(action => !action.CareAction.IsEnabled)) + if (primaryAction is null) { - return Results.BadRequest(new { error = "Disabled activities cannot be logged." }); + return Results.BadRequest(new { error = "Care activity has no configured actions." }); } var performedOn = request.PerformedOn ?? DateOnly.FromDateTime(DateTime.UtcNow); @@ -107,9 +107,9 @@ namespace plant_manager.Endpoints } var primaryAction = activity.PrimaryAction(); - if (!activity.IsEnabled || primaryAction is null || activity.Actions.Any(action => !action.CareAction.IsEnabled)) + if (primaryAction is null) { - return Results.BadRequest(new { error = "Disabled activities cannot be logged." }); + return Results.BadRequest(new { error = "Care activity has no configured actions." }); } var (resources, resourceError) = await BuildLogResources(request.Resources, activity, db); @@ -188,11 +188,6 @@ namespace plant_manager.Endpoints return ([], "One or more resources were not found."); } - if (resourcesById.Values.Any(resource => !resource.IsEnabled)) - { - return ([], "Disabled resources cannot be logged."); - } - return (requestedResources .Select(resource => new ActionLogResource { diff --git a/plant-manager/Endpoints/ActionResourceEndpoints.cs b/plant-manager/Endpoints/ActionResourceEndpoints.cs index 4b0a3b3..9f0afa5 100644 --- a/plant-manager/Endpoints/ActionResourceEndpoints.cs +++ b/plant-manager/Endpoints/ActionResourceEndpoints.cs @@ -11,9 +11,7 @@ namespace plant_manager.Endpoints app.MapGet("/api/action-resources", async (ApplicationDbContext db) => { var resources = await db.ActionResources - .OrderByDescending(resource => resource.IsEnabled) - .ThenBy(resource => resource.Category) - .ThenBy(resource => resource.Name) + .OrderBy(resource => resource.Name) .Select(resource => ActionResourceDto.FromActionResource(resource)) .ToListAsync(); @@ -37,9 +35,7 @@ namespace plant_manager.Endpoints var resource = new ActionResource { Name = name, - Category = string.IsNullOrWhiteSpace(request.Category) ? null : request.Category.Trim(), - Notes = string.IsNullOrWhiteSpace(request.Notes) ? null : request.Notes.Trim(), - IsEnabled = request.IsEnabled + Notes = string.IsNullOrWhiteSpace(request.Notes) ? null : request.Notes.Trim() }; db.ActionResources.Add(resource); @@ -70,9 +66,7 @@ namespace plant_manager.Endpoints } resource.Name = name; - resource.Category = string.IsNullOrWhiteSpace(request.Category) ? null : request.Category.Trim(); resource.Notes = string.IsNullOrWhiteSpace(request.Notes) ? null : request.Notes.Trim(); - resource.IsEnabled = request.IsEnabled; await db.SaveChangesAsync(); @@ -91,9 +85,7 @@ namespace plant_manager.Endpoints || await db.CareActivityActionResources.AnyAsync(activityResource => activityResource.ActionResourceId == id); if (isInUse) { - resource.IsEnabled = false; - await db.SaveChangesAsync(); - return Results.Conflict(new { error = "Resource is in use, so it was disabled instead of deleted." }); + return Results.Conflict(new { error = "Resource is in use." }); } db.ActionResources.Remove(resource); diff --git a/plant-manager/Endpoints/CareActionEndpoints.cs b/plant-manager/Endpoints/CareActionEndpoints.cs index 8df1ff9..ff9ff6a 100644 --- a/plant-manager/Endpoints/CareActionEndpoints.cs +++ b/plant-manager/Endpoints/CareActionEndpoints.cs @@ -11,8 +11,7 @@ namespace plant_manager.Endpoints app.MapGet("/api/care-actions", async (ApplicationDbContext db) => { var actions = await db.CareActions - .OrderByDescending(action => action.IsEnabled) - .ThenBy(action => action.Name) + .OrderBy(action => action.Name) .Select(action => CareActionDto.FromCareAction(action)) .ToListAsync(); @@ -36,8 +35,7 @@ namespace plant_manager.Endpoints var action = new CareAction { Name = name, - Description = string.IsNullOrWhiteSpace(request.Description) ? null : request.Description.Trim(), - IsEnabled = request.IsEnabled + Description = string.IsNullOrWhiteSpace(request.Description) ? null : request.Description.Trim() }; db.CareActions.Add(action); @@ -69,7 +67,6 @@ namespace plant_manager.Endpoints action.Name = name; action.Description = string.IsNullOrWhiteSpace(request.Description) ? null : request.Description.Trim(); - action.IsEnabled = request.IsEnabled; await db.SaveChangesAsync(); @@ -87,9 +84,7 @@ namespace plant_manager.Endpoints var hasLogs = await db.ActionLogs.AnyAsync(log => log.CareActionId == id); if (hasLogs) { - action.IsEnabled = false; - await db.SaveChangesAsync(); - return Results.Conflict(new { error = "Action has care history, so it was disabled instead of deleted." }); + return Results.Conflict(new { error = "Action has care history." }); } db.CareActions.Remove(action); diff --git a/plant-manager/Endpoints/CareActivityEndpoints.cs b/plant-manager/Endpoints/CareActivityEndpoints.cs index 505619b..142cd2b 100644 --- a/plant-manager/Endpoints/CareActivityEndpoints.cs +++ b/plant-manager/Endpoints/CareActivityEndpoints.cs @@ -16,8 +16,7 @@ namespace plant_manager.Endpoints .Include(activity => activity.Actions) .ThenInclude(action => action.Resources) .ThenInclude(resource => resource.ActionResource) - .OrderByDescending(activity => activity.IsEnabled) - .ThenBy(activity => activity.Name) + .OrderBy(activity => activity.Name) .Select(activity => CareActivityDto.FromCareActivity(activity)) .ToListAsync(); @@ -43,7 +42,6 @@ namespace plant_manager.Endpoints { Name = name, Notes = string.IsNullOrWhiteSpace(request.Notes) ? null : request.Notes.Trim(), - IsEnabled = request.IsEnabled, Actions = validation.Actions }; @@ -83,7 +81,6 @@ namespace plant_manager.Endpoints activity.Name = name; activity.Notes = string.IsNullOrWhiteSpace(request.Notes) ? null : request.Notes.Trim(); - activity.IsEnabled = request.IsEnabled; db.CareActivityActions.RemoveRange(activity.Actions); activity.Actions = validation.Actions; @@ -104,9 +101,7 @@ namespace plant_manager.Endpoints || await db.PlantCareSchedules.AnyAsync(schedule => schedule.CareActivityId == id); if (hasHistory) { - activity.IsEnabled = false; - await db.SaveChangesAsync(); - return Results.Conflict(new { error = "Activity is in use, so it was disabled instead of deleted." }); + return Results.Conflict(new { error = "Activity is in use." }); } db.CareActivities.Remove(activity); @@ -150,11 +145,6 @@ namespace plant_manager.Endpoints return ([], "One or more care actions were not found."); } - if (actionsById.Values.Any(action => !action.IsEnabled)) - { - return ([], "Disabled actions cannot be used in activities."); - } - var requestedResources = requestedActions .SelectMany(action => action.Resources ?? []) .GroupBy(resource => resource.ActionResourceId) @@ -181,11 +171,6 @@ namespace plant_manager.Endpoints return ([], "One or more resources were not found."); } - if (resourcesById.Values.Any(resource => !resource.IsEnabled)) - { - return ([], "Disabled resources cannot be used in activities."); - } - var activityActions = requestedActions .Select((actionRequest, index) => new CareActivityAction { diff --git a/plant-manager/Endpoints/CareTaskEndpoints.cs b/plant-manager/Endpoints/CareTaskEndpoints.cs index c7c53e7..1539294 100644 --- a/plant-manager/Endpoints/CareTaskEndpoints.cs +++ b/plant-manager/Endpoints/CareTaskEndpoints.cs @@ -21,10 +21,6 @@ namespace plant_manager.Endpoints .ThenInclude(activity => activity.Actions) .ThenInclude(action => action.Resources) .ThenInclude(resource => resource.ActionResource) - .Where(schedule => - schedule.IsEnabled - && schedule.CareActivity.Actions.All(action => action.CareAction.IsEnabled) - && schedule.CareActivity.IsEnabled) .OrderBy(schedule => schedule.Plant.Nickname) .ThenBy(schedule => schedule.CareActivity.Name) .ToListAsync(); @@ -86,17 +82,16 @@ namespace plant_manager.Endpoints } var primaryAction = activity.PrimaryAction(); - if (!activity.IsEnabled || primaryAction is null || activity.Actions.Any(action => !action.CareAction.IsEnabled)) + if (primaryAction is null) { - return Results.BadRequest(new { error = "Disabled activities cannot be logged." }); + return Results.BadRequest(new { error = "Care activity has no configured actions." }); } var today = DateOnly.FromDateTime(DateTime.UtcNow); var schedules = await db.PlantCareSchedules .Include(schedule => schedule.Plant) .Where(schedule => - schedule.IsEnabled - && schedule.CareActivityId == activity.Id + schedule.CareActivityId == activity.Id && plantIds.Contains(schedule.PlantId)) .ToListAsync(); var schedulePlantIds = schedules @@ -104,7 +99,7 @@ namespace plant_manager.Endpoints .ToHashSet(); if (schedulePlantIds.Count != plantIds.Count) { - return Results.BadRequest(new { error = "One or more plants do not have this enabled schedule." }); + return Results.BadRequest(new { error = "One or more plants do not have this schedule." }); } var latestLogs = await db.ActionLogs @@ -169,11 +164,6 @@ namespace plant_manager.Endpoints return Results.BadRequest(new { error = "One or more resources were not found." }); } - if (resourcesById.Values.Any(resource => !resource.IsEnabled)) - { - return Results.BadRequest(new { error = "Disabled resources cannot be logged." }); - } - var performedOn = request.PerformedOn ?? today; var notes = string.IsNullOrWhiteSpace(request.Notes) ? null : request.Notes.Trim(); var logs = schedules diff --git a/plant-manager/Endpoints/PlantCareScheduleEndpoints.cs b/plant-manager/Endpoints/PlantCareScheduleEndpoints.cs index 48d21a3..976dd96 100644 --- a/plant-manager/Endpoints/PlantCareScheduleEndpoints.cs +++ b/plant-manager/Endpoints/PlantCareScheduleEndpoints.cs @@ -31,9 +31,9 @@ namespace plant_manager.Endpoints } var primaryAction = activity.PrimaryAction(); - if (!activity.IsEnabled || primaryAction is null || activity.Actions.Any(action => !action.CareAction.IsEnabled)) + if (primaryAction is null) { - return Results.BadRequest(new { error = "Disabled activities cannot be scheduled." }); + return Results.BadRequest(new { error = "Care activity has no configured actions." }); } var plants = await db.Plants @@ -73,7 +73,6 @@ namespace plant_manager.Endpoints schedule.CareActionId = primaryAction.Id; schedule.CareActivityId = activity.Id; ApplyRecurrence(schedule, recurrence); - schedule.IsEnabled = request.IsEnabled; } await db.SaveChangesAsync(); diff --git a/plant-manager/Endpoints/PlantEndpoints.cs b/plant-manager/Endpoints/PlantEndpoints.cs index 2642c6c..2936637 100644 --- a/plant-manager/Endpoints/PlantEndpoints.cs +++ b/plant-manager/Endpoints/PlantEndpoints.cs @@ -206,8 +206,7 @@ namespace plant_manager.Endpoints null, "after", null, - 12, - true) + 12) ]; } @@ -234,11 +233,9 @@ namespace plant_manager.Endpoints } if (activitiesById.Values.Any(activity => - !activity.IsEnabled - || activity.PrimaryAction() is null - || activity.Actions.Any(action => !action.CareAction.IsEnabled))) + activity.PrimaryAction() is null)) { - return "Disabled activities cannot be scheduled."; + return "Care activities must have at least one action."; } var requestedActivityIds = activityIds.ToHashSet(); @@ -280,7 +277,6 @@ namespace plant_manager.Endpoints requestedSchedule.EndsAfterOccurrences, requestedSchedule.ScheduledFor, requestedSchedule.EveryDays)); - schedule.IsEnabled = requestedSchedule.IsEnabled; } return null; diff --git a/plant-manager/Endpoints/PlantFlagEndpoints.cs b/plant-manager/Endpoints/PlantFlagEndpoints.cs index 304b892..cb35953 100644 --- a/plant-manager/Endpoints/PlantFlagEndpoints.cs +++ b/plant-manager/Endpoints/PlantFlagEndpoints.cs @@ -11,8 +11,7 @@ namespace plant_manager.Endpoints app.MapGet("/api/plant-flags", async (ApplicationDbContext db) => { var definitions = await db.PlantFlagDefinitions - .OrderByDescending(definition => definition.IsEnabled) - .ThenBy(definition => definition.Name) + .OrderBy(definition => definition.Name) .Select(definition => PlantFlagDefinitionDto.FromDefinition(definition)) .ToListAsync(); @@ -37,8 +36,7 @@ namespace plant_manager.Endpoints var definition = new PlantFlagDefinition { Name = name, - Color = NormalizeColor(request.Color), - IsEnabled = request.IsEnabled + Color = NormalizeColor(request.Color) }; db.PlantFlagDefinitions.Add(definition); @@ -70,7 +68,6 @@ namespace plant_manager.Endpoints definition.Name = name; definition.Color = NormalizeColor(request.Color); - definition.IsEnabled = request.IsEnabled; await db.SaveChangesAsync(); @@ -88,9 +85,7 @@ namespace plant_manager.Endpoints var isUsed = await db.PlantFlags.AnyAsync(flag => flag.PlantFlagDefinitionId == id); if (isUsed) { - definition.IsEnabled = false; - await db.SaveChangesAsync(); - return Results.Conflict(new { error = "Flag is assigned to plants, so it was disabled instead of deleted." }); + return Results.Conflict(new { error = "Flag is assigned to plants." }); } db.PlantFlagDefinitions.Remove(definition); @@ -111,9 +106,9 @@ namespace plant_manager.Endpoints } var definition = await db.PlantFlagDefinitions.FindAsync(request.PlantFlagDefinitionId); - if (definition is null || !definition.IsEnabled) + if (definition is null) { - return Results.BadRequest(new { error = "Flag was not found or is disabled." }); + return Results.BadRequest(new { error = "Flag was not found." }); } var hasActiveFlag = await db.PlantFlags.AnyAsync(flag => diff --git a/plant-manager/Endpoints/PlantLocationEndpoints.cs b/plant-manager/Endpoints/PlantLocationEndpoints.cs index eaef1e3..1ca81f8 100644 --- a/plant-manager/Endpoints/PlantLocationEndpoints.cs +++ b/plant-manager/Endpoints/PlantLocationEndpoints.cs @@ -11,8 +11,7 @@ namespace plant_manager.Endpoints app.MapGet("/api/plant-locations", async (ApplicationDbContext db) => { var locations = await db.PlantLocations - .OrderByDescending(location => location.IsEnabled) - .ThenBy(location => location.Name) + .OrderBy(location => location.Name) .Select(location => PlantLocationDto.FromLocation(location)) .ToListAsync(); @@ -36,8 +35,7 @@ namespace plant_manager.Endpoints var location = new PlantLocation { Name = name, - Notes = string.IsNullOrWhiteSpace(request.Notes) ? null : request.Notes.Trim(), - IsEnabled = request.IsEnabled + Notes = string.IsNullOrWhiteSpace(request.Notes) ? null : request.Notes.Trim() }; db.PlantLocations.Add(location); @@ -69,7 +67,6 @@ namespace plant_manager.Endpoints location.Name = name; location.Notes = string.IsNullOrWhiteSpace(request.Notes) ? null : request.Notes.Trim(); - location.IsEnabled = request.IsEnabled; await db.SaveChangesAsync(); @@ -87,9 +84,7 @@ namespace plant_manager.Endpoints var isInUse = await db.Plants.AnyAsync(plant => plant.LocationId == id); if (isInUse) { - location.IsEnabled = false; - await db.SaveChangesAsync(); - return Results.Conflict(new { error = "Location is in use, so it was disabled instead of deleted." }); + return Results.Conflict(new { error = "Location is assigned to one or more plants." }); } db.PlantLocations.Remove(location);