mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-22 06:23:34 -07:00
feature: prep/cook/total time slots
This commit is contained in:
parent
b689c4715b
commit
420bba2e65
8 changed files with 209 additions and 59 deletions
|
@ -40,8 +40,8 @@ Backend
|
||||||
- [x] Recipes
|
- [x] Recipes
|
||||||
- [x] Images
|
- [x] Images
|
||||||
- [ ] Meal Plans
|
- [ ] Meal Plans
|
||||||
- [ ] Settings
|
- [x] Settings
|
||||||
- [ ] Themes
|
- [x] Themes
|
||||||
- [ ] Remove Print / Debug Code
|
- [ ] Remove Print / Debug Code
|
||||||
- [ ] Support how to Sections and how to steps
|
- [ ] Support how to Sections and how to steps
|
||||||
- [ ] Recipe request by category/tags
|
- [ ] Recipe request by category/tags
|
||||||
|
|
|
@ -7,21 +7,22 @@
|
||||||
- Fixed Images saved with no way to delete when add recipe via URL fails - Closes Issue #43
|
- Fixed Images saved with no way to delete when add recipe via URL fails - Closes Issue #43
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
- Additional database! sqlite is now supported! Closes #48
|
- Additional database! SQlite is now supported! Closes #48
|
||||||
- All site data is now backed up.
|
- All site data is now backed up.
|
||||||
|
- New backup import process with support for themes and site settings
|
||||||
|
|
||||||
|
### Code / Developer Improvements
|
||||||
### Code Improvements
|
|
||||||
- Unified Database Access Layers
|
- Unified Database Access Layers
|
||||||
- Poetry / pyproject.toml support
|
- Poetry / pyproject.toml support over requirements.txt
|
||||||
- Local development without database is now possible!
|
- Local development without database is now possible!
|
||||||
|
- Local mkdocs server added to docker-compose.dev.yml
|
||||||
- Major code refactoring to support new database layer
|
- Major code refactoring to support new database layer
|
||||||
- Global variable refactor
|
- Global variable refactor
|
||||||
|
|
||||||
### Break Changes
|
### Break Changes
|
||||||
|
|
||||||
!!! warning
|
!!! error "Breaking Changes"
|
||||||
As I've adopted the SQL database model I find that using 2 different types of databases will inevitably hinder development. As such after release v0.1.0 support for mongoDB will not longer be available. Prior to upgrading to v0.2.0 you will need to export your site and import your settings after updating. This should be a painless process and require minimal intervention on the users part. Moving forward we will do our best to minimize changes that require user intervention like this.
|
As I've adopted the SQL database model I find that using 2 different types of databases will inevitably hinder development. As such after release v0.1.0 support for mongoDB will no longer be available. Prior to upgrading to v0.2.0 you will need to export your site and import after updating. This should be a painless process and require minimal intervention on the users part. Moving forward we will do our best to minimize changes that require user intervention like this and make updates a smooth process.
|
||||||
|
|
||||||
|
|
||||||
## v0.0.2 - Pre-release Second Patch
|
## v0.0.2 - Pre-release Second Patch
|
||||||
|
|
|
@ -12,6 +12,26 @@
|
||||||
></v-file-input>
|
></v-file-input>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="3"></v-col>
|
<v-col cols="3"></v-col>
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<v-text-field
|
||||||
|
label="Total Time"
|
||||||
|
v-model="value.totalTime"
|
||||||
|
></v-text-field>
|
||||||
|
</v-col>
|
||||||
|
<v-col
|
||||||
|
><v-text-field
|
||||||
|
label="Prep Time"
|
||||||
|
v-model="value.prepTime"
|
||||||
|
></v-text-field
|
||||||
|
></v-col>
|
||||||
|
<v-col
|
||||||
|
><v-text-field
|
||||||
|
label="Cook Time / Perform Time"
|
||||||
|
v-model="value.performTime"
|
||||||
|
></v-text-field
|
||||||
|
></v-col>
|
||||||
|
</v-row>
|
||||||
</v-row>
|
</v-row>
|
||||||
<v-text-field class="my-3" label="Recipe Name" v-model="value.name">
|
<v-text-field class="my-3" label="Recipe Name" v-model="value.name">
|
||||||
</v-text-field>
|
</v-text-field>
|
||||||
|
|
102
frontend/src/components/Recipe/RecipeTimeCard.vue
Normal file
102
frontend/src/components/Recipe/RecipeTimeCard.vue
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
<template>
|
||||||
|
<v-card color="accent" class="transparent" tile :width="`${timeCardWidth}`">
|
||||||
|
<v-card-text
|
||||||
|
class="text-caption white--text"
|
||||||
|
v-if="totalTime || prepTime || performTime"
|
||||||
|
>
|
||||||
|
<v-row align="center" dense>
|
||||||
|
<v-col :cols="iconColumn">
|
||||||
|
<v-icon large color="white"> mdi-clock-outline </v-icon>
|
||||||
|
</v-col>
|
||||||
|
<v-divider
|
||||||
|
vertical
|
||||||
|
color="white"
|
||||||
|
class="my-1"
|
||||||
|
v-if="totalTime"
|
||||||
|
></v-divider>
|
||||||
|
<v-col v-if="totalTime">
|
||||||
|
<div><strong> Total Time </strong></div>
|
||||||
|
<div>{{ totalTime }}</div>
|
||||||
|
</v-col>
|
||||||
|
<v-divider
|
||||||
|
vertical
|
||||||
|
color="white"
|
||||||
|
class="my-1"
|
||||||
|
v-if="prepTime"
|
||||||
|
></v-divider>
|
||||||
|
<v-col v-if="prepTime">
|
||||||
|
<div><strong> Prep Time </strong></div>
|
||||||
|
<div>{{ prepTime }}</div>
|
||||||
|
</v-col>
|
||||||
|
<v-divider
|
||||||
|
vertical
|
||||||
|
color="white"
|
||||||
|
class="my-1"
|
||||||
|
v-if="performTime"
|
||||||
|
></v-divider>
|
||||||
|
<v-col v-if="performTime">
|
||||||
|
<div><strong> Cook Time </strong></div>
|
||||||
|
<div>{{ performTime }}</div>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
prepTime: String,
|
||||||
|
totalTime: String,
|
||||||
|
performTime: String,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
timeLength() {
|
||||||
|
let times = [];
|
||||||
|
let timeArray = [this.totalTime, this.prepTime, this.performTime];
|
||||||
|
timeArray.forEach((element) => {
|
||||||
|
if (element) {
|
||||||
|
times.push(element);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return times.length;
|
||||||
|
},
|
||||||
|
iconColumn() {
|
||||||
|
switch (this.timeLength) {
|
||||||
|
case 0:
|
||||||
|
return null;
|
||||||
|
case 1:
|
||||||
|
return 4;
|
||||||
|
case 2:
|
||||||
|
return 3;
|
||||||
|
case 3:
|
||||||
|
return 2;
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
timeCardWidth() {
|
||||||
|
let timeArray = [this.totalTime, this.prepTime, this.performTime];
|
||||||
|
let width = 120;
|
||||||
|
timeArray.forEach((element) => {
|
||||||
|
if (element) {
|
||||||
|
width += 70;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.$vuetify.breakpoint.name === "xs") {
|
||||||
|
return "100%";
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${width}px`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.transparent {
|
||||||
|
opacity: 70% !important;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -6,6 +6,12 @@
|
||||||
class="d-print-none"
|
class="d-print-none"
|
||||||
:key="imageKey"
|
:key="imageKey"
|
||||||
>
|
>
|
||||||
|
<RecipeTimeCard
|
||||||
|
class="force-bottom"
|
||||||
|
:prepTime="recipeDetails.prepTime"
|
||||||
|
:totalTime="recipeDetails.totalTime"
|
||||||
|
:performTime="recipeDetails.performTime"
|
||||||
|
/>
|
||||||
</v-img>
|
</v-img>
|
||||||
<ButtonRow
|
<ButtonRow
|
||||||
:open="showIcons"
|
:open="showIcons"
|
||||||
|
@ -49,6 +55,7 @@ import utils from "../utils";
|
||||||
import VJsoneditor from "v-jsoneditor";
|
import VJsoneditor from "v-jsoneditor";
|
||||||
import RecipeViewer from "../components/Recipe/RecipeViewer";
|
import RecipeViewer from "../components/Recipe/RecipeViewer";
|
||||||
import RecipeEditor from "../components/Recipe/RecipeEditor";
|
import RecipeEditor from "../components/Recipe/RecipeEditor";
|
||||||
|
import RecipeTimeCard from "../components/Recipe/RecipeTimeCard.vue";
|
||||||
import ButtonRow from "../components/UI/ButtonRow";
|
import ButtonRow from "../components/UI/ButtonRow";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -57,10 +64,11 @@ export default {
|
||||||
RecipeViewer,
|
RecipeViewer,
|
||||||
RecipeEditor,
|
RecipeEditor,
|
||||||
ButtonRow,
|
ButtonRow,
|
||||||
|
RecipeTimeCard,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
// CurrentRecipe: this.$route.params.recipe,
|
// currentRecipe: this.$route.params.recipe,
|
||||||
form: false,
|
form: false,
|
||||||
jsonEditor: false,
|
jsonEditor: false,
|
||||||
jsonEditorOptions: {
|
jsonEditorOptions: {
|
||||||
|
@ -99,7 +107,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
CurrentRecipe() {
|
currentRecipe() {
|
||||||
return this.$route.params.recipe;
|
return this.$route.params.recipe;
|
||||||
},
|
},
|
||||||
showIcons() {
|
showIcons() {
|
||||||
|
@ -118,7 +126,7 @@ export default {
|
||||||
this.fileObject = fileObject;
|
this.fileObject = fileObject;
|
||||||
},
|
},
|
||||||
async getRecipeDetails() {
|
async getRecipeDetails() {
|
||||||
this.recipeDetails = await api.recipes.requestDetails(this.CurrentRecipe);
|
this.recipeDetails = await api.recipes.requestDetails(this.currentRecipe);
|
||||||
this.form = false;
|
this.form = false;
|
||||||
},
|
},
|
||||||
getImage(image) {
|
getImage(image) {
|
||||||
|
@ -155,4 +163,10 @@ export default {
|
||||||
.disabled-card {
|
.disabled-card {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.force-bottom {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
Binary file not shown.
|
@ -1,25 +1,28 @@
|
||||||
{
|
{
|
||||||
"@context": "http://schema.org",
|
"@context": "http://schema.org",
|
||||||
"@type": "Recipe",
|
"@type": "Recipe",
|
||||||
"articleBody": "At her L.A. bakery Friends and Family, Roxana Jullapat bakes these blondies in a round cake pan, which ensures that each slice has a chewy, toasted edge and a soft center. \u201cThis caramel-flavored treat demonstrates the powerful pairing of brown butter and barley,\u201d Roxana writes in her cookbook Mother Grains (out April 2021). Barley flour gives baked goods a silky, chewy texture, dense crumb, and butterscotch-y flavor. Want to experiment? Make these with 3\u20444 cup (80 g) einkorn flour in place of the barley flour for an even chewier blondie.",
|
"articleBody": "\u201cMy great-grandmothers were Indigenous and mostly nomadic, which means lots of fungi foraging,\u201d says Maricela Vega, the chef at Atlanta restaurant 8ARM and founder of Chicomec\u00f3atl, an organization centering the foodways of Indigenous Mexican diaspora. \u201cWhen I serve lion\u2019s mane mushrooms to vegans they sometimes mistake them for chicken, but they\u2019re more affordable, better for the planet, and help strengthen your immune system! They grow wild during Georgia winters, but at-home cultivation kits are easy for those without forest access. I use pumpkin hot sauce, oil, and fresh herbs as a marinade, then bust out a baby grill or cast-iron skillet to get them nice and crispy.\u201d This is a multistep recipe but perfect for long winter days when you want to flood the house with toasty, irresistible aromas. When you chop the mixed herbs, save the stems and throw them into the blanching water for the vegetables to add flavor.",
|
||||||
"alternativeHeadline": "Barley flour gives these blondies a chewy texture and butterscotch-like flavor.",
|
"alternativeHeadline": "This dish is perfect for long winter days when you want to flood the house with toasty, irresistible aromas.",
|
||||||
"dateModified": "2021-01-11 14:23:12.455000",
|
"dateModified": "2021-01-11 18:32:43.962000",
|
||||||
"datePublished": "2021-01-12 04:00:00",
|
"datePublished": "2021-01-12 04:00:00",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"recipes",
|
"recipes",
|
||||||
"oil",
|
"healthyish",
|
||||||
"macadamia nut",
|
"vegan",
|
||||||
"vanilla",
|
"herb",
|
||||||
"butter",
|
"apple cider vinegar",
|
||||||
"flour",
|
|
||||||
"barley",
|
|
||||||
"kosher salt",
|
"kosher salt",
|
||||||
"brown sugar",
|
"carrot",
|
||||||
"egg",
|
"potato",
|
||||||
"vanilla extract",
|
"radicchio",
|
||||||
|
"mushroom",
|
||||||
|
"oyster mushrooms",
|
||||||
|
"oil",
|
||||||
|
"black pepper",
|
||||||
|
"lemon",
|
||||||
"web"
|
"web"
|
||||||
],
|
],
|
||||||
"thumbnailUrl": "https://assets.bonappetit.com/photos/5ff4b06a2f7e5df08337ef60/1:1/w_1005,h_1005,c_limit/Mother-Grains-Macadamia-and-Brown-Butter-Blondies.jpg",
|
"thumbnailUrl": "https://assets.bonappetit.com/photos/5ffc74b39cbb0a3c54d7400f/1:1/w_1199,h_1199,c_limit/HLY-Maricela-Vega-Grilled%20Mushrooms%20and%20Root%20Vegetables.jpg",
|
||||||
"publisher": {
|
"publisher": {
|
||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
"@type": "Organization",
|
"@type": "Organization",
|
||||||
|
@ -43,49 +46,59 @@
|
||||||
"author": [
|
"author": [
|
||||||
{
|
{
|
||||||
"@type": "Person",
|
"@type": "Person",
|
||||||
"name": "Roxana Jullapat",
|
"name": "Maricela Vega",
|
||||||
"sameAs": "https://bon-appetit.com/contributor/roxana-jullapat/"
|
"sameAs": "https://bon-appetit.com/contributor/maricela-vega/"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Barley flour gives these blondies a chewy texture and butterscotch-like flavor.",
|
"description": "This dish is perfect for long winter days when you want to flood the house with toasty, irresistible aromas.",
|
||||||
"image": "macadamia-and-brown-butter-blondies.jpg",
|
"image": "grilled-mushrooms-and-root-vegetables.jpg",
|
||||||
"headline": "Macadamia and Brown Butter Blondies",
|
"headline": "Grilled Mushrooms and Root Vegetables",
|
||||||
"name": "Macadamia and Brown Butter Blondies",
|
"name": "Grilled Mushrooms and Root Vegetables",
|
||||||
"recipeIngredient": [
|
"recipeIngredient": [
|
||||||
"Nonstick vegetable oil spray",
|
"1 cup Sesame Cr\u00e8me",
|
||||||
"\u00bd cup (65 g) whole raw or toasted macadamia nuts",
|
"2 Tbsp. Allium Confit",
|
||||||
"\u00bd vanilla bean, split lengthwise",
|
"2 Tbsp. finely chopped mixed tender herbs (parsley, oregano, and/or mint), stems reservedfor blanching vegetables",
|
||||||
"18 Tbsp. unsalted butter",
|
"2 Tbsp. apple cider vinegar",
|
||||||
"\u00be cup plus 2 Tbsp. (105 g) all-purpose flour",
|
"Kosher salt, freshly ground pepper",
|
||||||
"\u00be cup (85 g) barley flour",
|
"1 cup finely chopped mixed herbs (parsley, oregano, and/or mint), stems reserved for blanching vegetables",
|
||||||
"1\u00be tsp. baking powder",
|
"Kosher salt",
|
||||||
"1\u00bd tsp. Diamond Crystal or \u00be tsp. Morton kosher salt",
|
"4 medium carrots (about 1 lb.), preferably rainbow, scrubbed, halved lengthwise, cut crosswise into thirds",
|
||||||
"1 cup plus 7 Tbsp. (packed; 285 g) dark brown sugar",
|
"4 lb. baby potatoes, halved",
|
||||||
"2 large eggs",
|
"1 head of radicchio, coarsely chopped, divided",
|
||||||
"1 tsp. vanilla extract",
|
"1 lb. lion\u2019s mane, king trumpet, or oyster mushrooms, cut into 2\" pieces",
|
||||||
"2 pints ice cream of choice (optional)"
|
"\u00bd cup Pumpkin Hot Sauce",
|
||||||
|
"\u00bd cup grapeseed or vegetable oil",
|
||||||
|
"Freshly ground black pepper",
|
||||||
|
"1 cup Spiced Pecans",
|
||||||
|
"1 lemon, halved"
|
||||||
],
|
],
|
||||||
"recipeInstructions": [
|
"recipeInstructions": [
|
||||||
{
|
{
|
||||||
"text": "Preheat oven to 350\u00b0. Lightly coat a 9\"-diameter cake pan with nonstick spray and line bottom with a parchment paper round. If using raw macadamia nuts, toast on a rimmed baking sheet, tossing once, until golden, 8\u201310 minutes. Let cool, then coarsely chop."
|
"text": "Pur\u00e9e Sesame Cr\u00e8me, Allium Confit, chopped herbs, and vinegar in a blender on high speed, adding ice water by the tablespoonful as needed to achieve a pourable consistency, until smooth and creamy. Season sauce with salt and pepper."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "Scrape vanilla seeds into a small saucepan; add pod and butter. Set over medium-low heat and cook, stirring occasionally, until butter foams, then browns, 6\u20138 minutes. Transfer to a medium bowl, scraping in all of the browned bits. Using tongs, remove and discard vanilla pod."
|
"text": "Fill a large pot three quarters full with water, add reserved herb stems, and season heavily with salt. Bring water to a boil, then add carrots and cook until just tender, about 3 minutes. Using a slotted spoon, immediately transfer carrots to a large bowl of ice water and let cool."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "Whisk all-purpose and barley flours, baking powder, and salt in another medium bowl. Add brown sugar to brown butter and stir to combine. Add eggs one at a time, stirring well after each addition. Stir in dry ingredients, then vanilla extract and nuts. Scrape batter into prepared pan; smooth top."
|
"text": "Place potatoes in same pot and return to a boil. Cook until tender (flesh should be easy to pierce with a fork), about 10 minutes. Using slotted spoon, transfer potatoes to bowl of ice water and let cool. Drain carrots and potatoes; place in a clean large bowl and add half of the radicchio. Place mushrooms in a medium bowl."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "Bake blondies, rotating halfway through, until top is golden brown and a tester inserted into the center comes out clean, 40\u201345 minutes. Let cool."
|
"text": "Whisk Pumpkin Hot Sauce, oil, and chopped herbs in another medium bowl. Pour half of mixture over carrots and potatoes and the other half over mushrooms; toss each to coat. Season with salt and pepper."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "Turn out blondies, remove parchment, and cut into 12 wedges. Serve each with a scoop of ice cream if desired."
|
"text": "Prepare a grill for medium-high heat. (Alternatively, heat a large cast-iron skillet over medium-high.) Grill mushrooms, turning occasionally, until deep golden brown and crisp around the edges (or cook in batches, stirring often, if using a skillet), 12\u201314 minutes. Transfer mushrooms to a large shallow serving bowl."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Grill carrots, potatoes, and radicchio, turning occasionally, until deep golden brown all over (or cook in batches, tossing often, if using a skillet), about 4 minutes. Transfer vegetables to bowl with mushrooms and toss to combine."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "To serve, drizzle generously with sesame sauce; top with Spiced Pecans and remaining radicchio. Squeeze juice from each lemon half over."
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"recipeYield": "Makes 12",
|
"recipeYield": "4 Servings",
|
||||||
"url": "https://www.bonappetit.com/recipe/macadamia-and-brown-butter-blondies",
|
"url": "https://www.bonappetit.com/recipe/grilled-mushrooms-and-root-vegetables",
|
||||||
"slug": "macadamia-and-brown-butter-blondies",
|
"slug": "grilled-mushrooms-and-root-vegetables",
|
||||||
"orgURL": "https://www.bonappetit.com/recipe/macadamia-and-brown-butter-blondies",
|
"orgURL": "https://www.bonappetit.com/recipe/grilled-mushrooms-and-root-vegetables",
|
||||||
"categories": [],
|
"categories": [],
|
||||||
"tags": [],
|
"tags": [],
|
||||||
"dateAdded": null,
|
"dateAdded": null,
|
||||||
|
|
|
@ -28,9 +28,9 @@ class Recipe(BaseModel):
|
||||||
recipeIngredient: Optional[list]
|
recipeIngredient: Optional[list]
|
||||||
recipeInstructions: Optional[list]
|
recipeInstructions: Optional[list]
|
||||||
|
|
||||||
totalTime: Optional[Any]
|
totalTime: Optional[str] = None
|
||||||
prepTime: Optional[str]
|
prepTime: Optional[str] = None
|
||||||
performTime: Optional[str]
|
performTime: Optional[str] = None
|
||||||
|
|
||||||
# Mealie Specific
|
# Mealie Specific
|
||||||
slug: Optional[str] = ""
|
slug: Optional[str] = ""
|
||||||
|
@ -107,11 +107,11 @@ class Recipe(BaseModel):
|
||||||
except:
|
except:
|
||||||
recipe_dict["image"] = "no image"
|
recipe_dict["image"] = "no image"
|
||||||
|
|
||||||
try:
|
# try:
|
||||||
total_time = recipe_dict.get("totalTime")
|
# total_time = recipe_dict.get("totalTime")
|
||||||
recipe_dict["totalTime"] = str(total_time)
|
# recipe_dict["totalTime"] = str(total_time)
|
||||||
except:
|
# except:
|
||||||
pass
|
# pass
|
||||||
|
|
||||||
recipe_doc = db.recipes.save_new(recipe_dict)
|
recipe_doc = db.recipes.save_new(recipe_dict)
|
||||||
recipe = Recipe(**recipe_doc)
|
recipe = Recipe(**recipe_doc)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue