Skip to content

Commit

Permalink
Merge branch 'mealie-next' into fix/sort-food-by-label
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-genson authored Dec 5, 2024
2 parents 79a30be + c691418 commit 0f5461a
Show file tree
Hide file tree
Showing 121 changed files with 2,234 additions and 425 deletions.
4 changes: 2 additions & 2 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.224.2/containers/python-3/.devcontainer/base.Dockerfile

# [Choice] Python version (use -bullseye variants on local arm64/Apple Silicon): 3, 3.10, 3.9, 3.8, 3.7, 3.6, 3-bullseye, 3.10-bullseye, 3.9-bullseye, 3.8-bullseye, 3.7-bullseye, 3.6-bullseye, 3-buster, 3.10-buster, 3.9-buster, 3.8-buster, 3.7-buster, 3.6-buster
ARG VARIANT="3.10-bullseye"
FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT}
ARG VARIANT="3.12-bullseye"
FROM mcr.microsoft.com/devcontainers/python:${VARIANT}

# [Choice] Node.js version: none, lts/*, 16, 14, 12, 10
ARG NODE_VERSION="none"
Expand Down
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// Update 'VARIANT' to pick a Python version: 3, 3.10, 3.9, 3.8, 3.7, 3.6
// Append -bullseye or -buster to pin to an OS version.
// Use -bullseye variants on local on arm64/Apple Silicon.
"VARIANT": "3.10-bullseye",
"VARIANT": "3.12-bullseye",
// Options
"NODE_VERSION": "16"
}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/partial-backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
- name: Set up python
uses: actions/setup-python@v5
with:
python-version: "3.10"
python-version: "3.12"

- name: Install Poetry
uses: snok/install-poetry@v1
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/scheduled-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
python-version: "3.12"

- name: Set PY
shell: bash
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ repos:
exclude: ^tests/data/
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.8.0
rev: v0.8.1
hooks:
- id: ruff
- id: ruff-format
2 changes: 1 addition & 1 deletion Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ tasks:
py:migrate:
desc: generates a new database migration file e.g. task py:migrate -- "add new column"
cmds:
- poetry run alembic revision --autogenerate -m "{{ .CLI_ARGS }}"
- poetry run alembic --config mealie/alembic/alembic.ini revision --autogenerate -m "{{ .CLI_ARGS }}"
- task: py:format

ui:build:
Expand Down
6 changes: 1 addition & 5 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ RUN yarn generate
###############################################
# Base Image - Python
###############################################
FROM python:3.10-slim as python-base
FROM python:3.12-slim as python-base

ENV MEALIE_HOME="/app"

Expand Down Expand Up @@ -109,10 +109,6 @@ COPY --from=crfpp /usr/local/bin/crf_test /usr/local/bin/crf_test
COPY ./mealie $MEALIE_HOME/mealie
COPY ./poetry.lock ./pyproject.toml $MEALIE_HOME/

# Alembic
COPY ./alembic $MEALIE_HOME/alembic
COPY ./alembic.ini $MEALIE_HOME/

# venv already has runtime deps installed we get a quicker install
WORKDIR $MEALIE_HOME
RUN . $VENV_PATH/bin/activate && poetry install -E pgsql --only main
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Make sure the VSCode Dev Containers extension is installed, then select "Dev Con

### Prerequisites

- [Python 3.10](https://www.python.org/downloads/)
- [Python 3.12](https://www.python.org/downloads/)
- [Poetry](https://python-poetry.org/docs/#installation)
- [Node v16.x](https://nodejs.org/en/)
- [yarn](https://classic.yarnpkg.com/lang/en/docs/install/#mac-stable)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Mealie supports 3rd party authentication via [OpenID Connect (OIDC)](https://openid.net/connect/), an identity layer built on top of OAuth2. OIDC is supported by many Identity Providers (IdP), including:

- [Authentik](https://goauthentik.io/integrations/sources/oauth/#openid-connect)
- [Authelia](https://www.authelia.com/configuration/identity-providers/open-id-connect/)
- [Authelia](https://www.authelia.com/integration/openid-connect/mealie/)
- [Keycloak](https://www.keycloak.org/docs/latest/securing_apps/#_oidc)
- [Okta](https://www.okta.com/openid-connect/)

Expand Down
8 changes: 8 additions & 0 deletions frontend/assets/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,11 @@
.v-card__title {
word-break: normal !important;
}

.text-hide-overflow {
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
}
29 changes: 28 additions & 1 deletion frontend/components/Domain/QueryFilterBuilder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@
</v-container>
</v-card-text>
<v-card-actions>
<v-container fluid class="d-flex justify-end pa-0">
<v-container fluid class="d-flex justify-end pa-0 mx-2">
<v-checkbox
v-model="showAdvanced"
hide-details
Expand Down Expand Up @@ -431,6 +431,7 @@ export default defineComponent({
state.qfValid = !!qf;
context.emit("input", qf || undefined);
context.emit("inputJSON", qf ? buildQueryFilterJSON() : undefined);
},
{
deep: true
Expand Down Expand Up @@ -543,6 +544,32 @@ export default defineComponent({
initFieldsError(`Error initializing fields: ${(error || "").toString()}`);
}
function buildQueryFilterJSON(): QueryFilterJSON {
const parts = fields.value.map((field) => {
const part: QueryFilterJSONPart = {
attributeName: field.name,
leftParenthesis: field.leftParenthesis,
rightParenthesis: field.rightParenthesis,
logicalOperator: field.logicalOperator?.value,
relationalOperator: field.relationalOperatorValue?.value,
};
if (field.fieldOptions?.length || isOrganizerType(field.type)) {
part.value = field.values.map((value) => value.toString());
} else if (field.type === "boolean") {
part.value = field.value ? "true" : "false";
} else {
part.value = (field.value || "").toString();
}
return part;
});
const qfJSON = { parts } as QueryFilterJSON;
console.debug(`Built query filter JSON: ${JSON.stringify(qfJSON)}`);
return qfJSON;
}
const attrs = computed(() => {
const baseColMaxWidth = 55;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
<template>
<div v-if="dialog">
<BaseDialog v-if="shoppingListDialog && ready" v-model="dialog" :title="$t('recipe.add-to-list')" :icon="$globals.icons.cartCheck">
<v-container v-if="!shoppingListChoices.length">
<BasePageTitle>
<template #title>{{ $t('shopping-list.no-shopping-lists-found') }}</template>
</BasePageTitle>
</v-container>
<v-card-text>
<v-card
v-for="list in shoppingListChoices"
Expand Down
118 changes: 118 additions & 0 deletions frontend/components/Domain/Recipe/RecipeSuggestion.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<template>
<v-container class="elevation-3">
<v-row no-gutters>
<v-col cols="12">
<RecipeCardMobile
:name="recipe.name"
:description="recipe.description"
:slug="recipe.slug"
:rating="recipe.rating"
:image="recipe.image"
:recipe-id="recipe.id"
/>
</v-col>
<div v-for="(organizer, idx) in missingOrganizers" :key="idx">
<v-col
v-if="organizer.show"
cols="12"
>
<div class="d-flex flex-row flex-wrap align-center pt-2">
<v-icon class="ma-0 pa-0">{{ organizer.icon }}</v-icon>
<v-card-text class="mr-0 my-0 pl-1 py-0" style="width: min-content;">
{{ $tc("recipe-finder.missing") }}:
</v-card-text>
<v-chip
v-for="item in organizer.items"
:key="item.item.id"
label
color="secondary custom-transparent"
class="mr-2 my-1"
>
<v-checkbox dark :ripple="false" @click="handleCheckbox(item)">
<template #label>
{{ organizer.getLabel(item.item) }}
</template>
</v-checkbox>
</v-chip>
</div>
</v-col>
</div>
</v-row>
</v-container>
</template>

<script lang="ts">
import { computed, defineComponent, reactive, useContext } from "@nuxtjs/composition-api";
import RecipeCardMobile from "./RecipeCardMobile.vue";
import { IngredientFood, RecipeSummary, RecipeTool } from "~/lib/api/types/recipe";
interface Organizer {
type: "food" | "tool";
item: IngredientFood | RecipeTool;
selected: boolean;
}
export default defineComponent({
components: { RecipeCardMobile },
props: {
recipe: {
type: Object as () => RecipeSummary,
required: true,
},
missingFoods: {
type: Array as () => IngredientFood[] | null,
default: null,
},
missingTools: {
type: Array as () => RecipeTool[] | null,
default: null,
},
disableCheckbox: {
type: Boolean,
default: false,
},
},
setup(props, context) {
const { $globals } = useContext();
const missingOrganizers = computed(() => [
{
type: "food",
show: props.missingFoods?.length,
icon: $globals.icons.foods,
items: props.missingFoods ? props.missingFoods.map((food) => {
return reactive({type: "food", item: food, selected: false} as Organizer);
}) : [],
getLabel: (item: IngredientFood) => item.pluralName || item.name,
},
{
type: "tool",
show: props.missingTools?.length,
icon: $globals.icons.tools,
items: props.missingTools ? props.missingTools.map((tool) => {
return reactive({type: "tool", item: tool, selected: false} as Organizer);
}) : [],
getLabel: (item: RecipeTool) => item.name,
}
])
function handleCheckbox(organizer: Organizer) {
if (props.disableCheckbox) {
return;
}
organizer.selected = !organizer.selected;
if (organizer.selected) {
context.emit(`add-${organizer.type}`, organizer.item);
}
else {
context.emit(`remove-${organizer.type}`, organizer.item);
}
}
return {
missingOrganizers,
handleCheckbox,
};
}
});
</script>
8 changes: 7 additions & 1 deletion frontend/components/Layout/DefaultLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,13 @@ export default defineComponent({
icon: $globals.icons.silverwareForkKnife,
to: `/g/${groupSlug.value}`,
title: i18n.tc("general.recipes"),
restricted: true,
restricted: false,
},
{
icon: $globals.icons.search,
to: `/g/${groupSlug.value}/recipes/finder`,
title: i18n.tc("recipe-finder.recipe-finder"),
restricted: false,
},
{
icon: $globals.icons.calendarMultiselect,
Expand Down
10 changes: 8 additions & 2 deletions frontend/components/global/BaseDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,13 @@
</v-btn>
<v-spacer></v-spacer>

<slot name="custom-card-action"></slot>
<BaseButton v-if="$listeners.delete" delete secondary @click="deleteEvent" />
<BaseButton
v-if="$listeners.confirm"
:color="color"
type="submit"
:disabled="submitDisabled"
@click="
$emit('confirm');
dialog = false;
Expand All @@ -60,8 +62,12 @@
</template>
{{ $t("general.confirm") }}
</BaseButton>
<slot name="custom-card-action"></slot>
<BaseButton v-if="$listeners.submit" type="submit" :disabled="submitDisabled" @click="submitEvent">
<BaseButton
v-if="$listeners.submit"
type="submit"
:disabled="submitDisabled"
@click="submitEvent"
>
{{ submitText }}
<template v-if="submitIcon" #icon>
{{ submitIcon }}
Expand Down
33 changes: 33 additions & 0 deletions frontend/composables/use-users/preferences.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Ref, useContext } from "@nuxtjs/composition-api";
import { useLocalStorage, useSessionStorage } from "@vueuse/core";
import { RegisteredParser, TimelineEventType } from "~/lib/api/types/recipe";
import { QueryFilterJSON } from "~/lib/api/types/response";

export interface UserPrintPreferences {
imagePosition: string;
Expand Down Expand Up @@ -49,6 +50,17 @@ export interface UserCookbooksPreferences {
hideOtherHouseholds: boolean;
}

export interface UserRecipeFinderPreferences {
foodIds: string[];
toolIds: string[];
queryFilter: string;
queryFilterJSON: QueryFilterJSON;
maxMissingFoods: number;
maxMissingTools: number;
includeFoodsOnHand: boolean;
includeToolsOnHand: boolean;
}

export function useUserMealPlanPreferences(): Ref<UserMealPlanPreferences> {
const fromStorage = useLocalStorage(
"meal-planner-preferences",
Expand Down Expand Up @@ -171,3 +183,24 @@ export function useCookbookPreferences(): Ref<UserCookbooksPreferences> {

return fromStorage;
}

export function useRecipeFinderPreferences(): Ref<UserRecipeFinderPreferences> {
const fromStorage = useLocalStorage(
"recipe-finder-preferences",
{
foodIds: [],
toolIds: [],
queryFilter: "",
queryFilterJSON: { parts: [] } as QueryFilterJSON,
maxMissingFoods: 20,
maxMissingTools: 20,
includeFoodsOnHand: true,
includeToolsOnHand: true,
},
{ mergeDefaults: true }
// we cast to a Ref because by default it will return an optional type ref
// but since we pass defaults we know all properties are set.
) as unknown as Ref<UserRecipeFinderPreferences>;

return fromStorage;
}
Loading

0 comments on commit 0f5461a

Please sign in to comment.